+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-AE.js b/vendors/DateJS/build/date-ar-AE.js
new file mode 100644
index 0000000..330c843
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-AE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-BH.js b/vendors/DateJS/build/date-ar-BH.js
new file mode 100644
index 0000000..37ca5d0
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-BH.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-DZ.js b/vendors/DateJS/build/date-ar-DZ.js
new file mode 100644
index 0000000..41fad4d
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-DZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-EG.js b/vendors/DateJS/build/date-ar-EG.js
new file mode 100644
index 0000000..5e69239
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-EG.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-IQ.js b/vendors/DateJS/build/date-ar-IQ.js
new file mode 100644
index 0000000..eab5a5d
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-IQ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-JO.js b/vendors/DateJS/build/date-ar-JO.js
new file mode 100644
index 0000000..04aebb8
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-JO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-KW.js b/vendors/DateJS/build/date-ar-KW.js
new file mode 100644
index 0000000..8a7abbd
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-KW.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-LB.js b/vendors/DateJS/build/date-ar-LB.js
new file mode 100644
index 0000000..b977d45
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-LB.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-LY.js b/vendors/DateJS/build/date-ar-LY.js
new file mode 100644
index 0000000..0dcbfad
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-LY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-MA.js b/vendors/DateJS/build/date-ar-MA.js
new file mode 100644
index 0000000..811fc33
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-MA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-OM.js b/vendors/DateJS/build/date-ar-OM.js
new file mode 100644
index 0000000..38c6804
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-OM.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-QA.js b/vendors/DateJS/build/date-ar-QA.js
new file mode 100644
index 0000000..71677cc
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-QA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-SA.js b/vendors/DateJS/build/date-ar-SA.js
new file mode 100644
index 0000000..0947ac1
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-SA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-SY.js b/vendors/DateJS/build/date-ar-SY.js
new file mode 100644
index 0000000..d7a8051
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-SY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-TN.js b/vendors/DateJS/build/date-ar-TN.js
new file mode 100644
index 0000000..a10039a
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-TN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ar-YE.js b/vendors/DateJS/build/date-ar-YE.js
new file mode 100644
index 0000000..bbbb920
--- /dev/null
+++ b/vendors/DateJS/build/date-ar-YE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-az-Cyrl-AZ.js b/vendors/DateJS/build/date-az-Cyrl-AZ.js
new file mode 100644
index 0000000..c3f5146
--- /dev/null
+++ b/vendors/DateJS/build/date-az-Cyrl-AZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-az-Latn-AZ.js b/vendors/DateJS/build/date-az-Latn-AZ.js
new file mode 100644
index 0000000..b1f747e
--- /dev/null
+++ b/vendors/DateJS/build/date-az-Latn-AZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-be-BY.js b/vendors/DateJS/build/date-be-BY.js
new file mode 100644
index 0000000..28df467
--- /dev/null
+++ b/vendors/DateJS/build/date-be-BY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-bg-BG.js b/vendors/DateJS/build/date-bg-BG.js
new file mode 100644
index 0000000..4147c0c
--- /dev/null
+++ b/vendors/DateJS/build/date-bg-BG.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-bs-Latn-BA.js b/vendors/DateJS/build/date-bs-Latn-BA.js
new file mode 100644
index 0000000..ada330a
--- /dev/null
+++ b/vendors/DateJS/build/date-bs-Latn-BA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ca-ES.js b/vendors/DateJS/build/date-ca-ES.js
new file mode 100644
index 0000000..0e24cea
--- /dev/null
+++ b/vendors/DateJS/build/date-ca-ES.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-cs-CZ.js b/vendors/DateJS/build/date-cs-CZ.js
new file mode 100644
index 0000000..0e09c77
--- /dev/null
+++ b/vendors/DateJS/build/date-cs-CZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-cy-GB.js b/vendors/DateJS/build/date-cy-GB.js
new file mode 100644
index 0000000..6150570
--- /dev/null
+++ b/vendors/DateJS/build/date-cy-GB.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-da-DK.js b/vendors/DateJS/build/date-da-DK.js
new file mode 100644
index 0000000..cf6a886
--- /dev/null
+++ b/vendors/DateJS/build/date-da-DK.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-de-AT.js b/vendors/DateJS/build/date-de-AT.js
new file mode 100644
index 0000000..e288047
--- /dev/null
+++ b/vendors/DateJS/build/date-de-AT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-de-CH.js b/vendors/DateJS/build/date-de-CH.js
new file mode 100644
index 0000000..4e231c9
--- /dev/null
+++ b/vendors/DateJS/build/date-de-CH.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-de-DE.js b/vendors/DateJS/build/date-de-DE.js
new file mode 100644
index 0000000..964e7cc
--- /dev/null
+++ b/vendors/DateJS/build/date-de-DE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-de-LI.js b/vendors/DateJS/build/date-de-LI.js
new file mode 100644
index 0000000..8e70b81
--- /dev/null
+++ b/vendors/DateJS/build/date-de-LI.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-de-LU.js b/vendors/DateJS/build/date-de-LU.js
new file mode 100644
index 0000000..14adf96
--- /dev/null
+++ b/vendors/DateJS/build/date-de-LU.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-dv-MV.js b/vendors/DateJS/build/date-dv-MV.js
new file mode 100644
index 0000000..052777e
--- /dev/null
+++ b/vendors/DateJS/build/date-dv-MV.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-el-GR.js b/vendors/DateJS/build/date-el-GR.js
new file mode 100644
index 0000000..eab9e3b
--- /dev/null
+++ b/vendors/DateJS/build/date-el-GR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-029.js b/vendors/DateJS/build/date-en-029.js
new file mode 100644
index 0000000..841d6a6
--- /dev/null
+++ b/vendors/DateJS/build/date-en-029.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-AU.js b/vendors/DateJS/build/date-en-AU.js
new file mode 100644
index 0000000..a364990
--- /dev/null
+++ b/vendors/DateJS/build/date-en-AU.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-BZ.js b/vendors/DateJS/build/date-en-BZ.js
new file mode 100644
index 0000000..79b3d5c
--- /dev/null
+++ b/vendors/DateJS/build/date-en-BZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-CA.js b/vendors/DateJS/build/date-en-CA.js
new file mode 100644
index 0000000..1a7edbc
--- /dev/null
+++ b/vendors/DateJS/build/date-en-CA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-GB.js b/vendors/DateJS/build/date-en-GB.js
new file mode 100644
index 0000000..601613d
--- /dev/null
+++ b/vendors/DateJS/build/date-en-GB.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-IE.js b/vendors/DateJS/build/date-en-IE.js
new file mode 100644
index 0000000..c2fc858
--- /dev/null
+++ b/vendors/DateJS/build/date-en-IE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-JM.js b/vendors/DateJS/build/date-en-JM.js
new file mode 100644
index 0000000..41b2da5
--- /dev/null
+++ b/vendors/DateJS/build/date-en-JM.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-NZ.js b/vendors/DateJS/build/date-en-NZ.js
new file mode 100644
index 0000000..1d7346e
--- /dev/null
+++ b/vendors/DateJS/build/date-en-NZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-PH.js b/vendors/DateJS/build/date-en-PH.js
new file mode 100644
index 0000000..77b39f5
--- /dev/null
+++ b/vendors/DateJS/build/date-en-PH.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-TT.js b/vendors/DateJS/build/date-en-TT.js
new file mode 100644
index 0000000..fc3c91b
--- /dev/null
+++ b/vendors/DateJS/build/date-en-TT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-US.js b/vendors/DateJS/build/date-en-US.js
new file mode 100644
index 0000000..0ce137a
--- /dev/null
+++ b/vendors/DateJS/build/date-en-US.js
@@ -0,0 +1,4096 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-beta-2014-03-25
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ // private
+ var validate = function (n, min, max, name) {
+ name = name ? name : "Object";
+ if (typeof n === "undefined") {
+ return false;
+ } else if (typeof n !== "number") {
+ throw new TypeError(n + " is not a Number.");
+ } else if (n < min || n > max) {
+ // As failing validation is *not* an exceptional circumstance
+ // lets not throw a RangeError Exception here.
+ // It's semantically correct but it's not sensible.
+ return false;
+ }
+ return true;
+ };
+
+ /**
+ * Validates the number is within an acceptable range for milliseconds [0-999].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMillisecond = function (value) {
+ return validate(value, 0, 999, "millisecond");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for seconds [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateSecond = function (value) {
+ return validate(value, 0, 59, "second");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for minutes [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMinute = function (value) {
+ return validate(value, 0, 59, "minute");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for hours [0-23].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateHour = function (value) {
+ return validate(value, 0, 23, "hour");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateDay = function (value, year, month) {
+ return validate(value, 1, $D.getDaysInMonth(year, month), "day");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for months [0-11].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateWeek = function (value) {
+ return validate(value, 0, 53, "week");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for months [0-11].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMonth = function (value) {
+ return validate(value, 0, 11, "month");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for years.
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateYear = function (value) {
+ /**
+ * Per ECMAScript spec the range of times supported by Date objects is
+ * exactly –100,000,000 days to 100,000,000 days measured relative to
+ * midnight at the beginning of 01 January, 1970 UTC.
+ * This gives a range of 8,640,000,000,000,000 milliseconds to either
+ * side of 01 January, 1970 UTC.
+ *
+ * Earliest possible date: Tue, 20 Apr 271,822 B.C. 00:00:00 UTC
+ * Latest possible date: Sat, 13 Sep 275,760 00:00:00 UTC
+ */
+
+ return validate(value, -271822, 275760, "year");
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ if ($D.validateMillisecond(config.millisecond)) {
+ this.addMilliseconds(config.millisecond - this.getMilliseconds());
+ }
+
+ if ($D.validateSecond(config.second)) {
+ this.addSeconds(config.second - this.getSeconds());
+ }
+
+ if ($D.validateMinute(config.minute)) {
+ this.addMinutes(config.minute - this.getMinutes());
+ }
+
+ if ($D.validateHour(config.hour)) {
+ this.addHours(config.hour - this.getHours());
+ }
+
+ if ($D.validateMonth(config.month)) {
+ this.addMonths(config.month - this.getMonth());
+ }
+
+ if ($D.validateYear(config.year)) {
+ this.addYears(config.year - this.getFullYear());
+ }
+
+ /* day has to go last because you can't validate the day without first knowing the month */
+ if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ if (config.timezone) {
+ this.setTimezone(config.timezone);
+ }
+
+ if (config.timezoneOffset) {
+ this.setTimezoneOffset(config.timezoneOffset);
+ }
+
+ if (config.week && $D.validateWeek(config.week)) {
+ this.setWeek(config.week);
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = function (dayOfWeek, orient) {
+ var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
+ return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
+ };
+
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = function (month, orient) {
+ var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
+ return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
+ };
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ + CUSTOM DATE AND TIME FORMAT STRINGS + Format Description Example + ------ --------------------------------------------------------------------------- ----------------------- + s The seconds of the minute between 0-59. "0" to "59" + ss The seconds of the minute with leading zero if required. "00" to "59" + + m The minute of the hour between 0-59. "0" or "59" + mm The minute of the hour with leading zero if required. "00" or "59" + + h The hour of the day between 1-12. "1" to "12" + hh The hour of the day with leading zero if required. "01" to "12" + + H The hour of the day between 0-23. "0" to "23" + HH The hour of the day with leading zero if required. "00" to "23" + + d The day of the month between 1 and 31. "1" to "31" + dd The day of the month with leading zero if required. "01" to "31" + ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun" + dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday" + + M The month of the year between 1-12. "1" to "12" + MM The month of the year with leading zero if required. "01" to "12" + MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec" + MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December" + + yy The year as a two-digit number. "99" or "08" + yyyy The full four digit year. "1999" or "2008" + + t Displays the first character of the A.M./P.M. designator. "A" or "P" + Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator + tt Displays the A.M./P.M. designator. "AM" or "PM" + Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator + + S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th" + +|| *Format* || *Description* || *Example* || +|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" || +|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" || +|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" || +|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" || +|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" || +|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" || +|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" || +|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" || +|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" || +|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" || + + + STANDARD DATE AND TIME FORMAT STRINGS + Format Description Example ("en-US") + ------ --------------------------------------------------------------------------- ----------------------- + d The CultureInfo shortDate Format Pattern "M/d/yyyy" + D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy" + F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt" + m The CultureInfo monthDay Format Pattern "MMMM dd" + r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT" + s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss" + t The CultureInfo shortTime Format Pattern "h:mm tt" + T The CultureInfo longTime Format Pattern "h:mm:ss tt" + u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ" + y The CultureInfo yearMonth Format Pattern "MMMM, yyyy" ++ * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @return {String} A string representation of the current Date object. + */ + + var ord = function (n) { + switch (n * 1) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } + }; + $P.toString = function (format, ignoreStandards) { + var x = this; + + // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and + // may vary by culture. + if (!ignoreStandards && format && format.length === 1) { + var y, c = Date.CultureInfo.formatPatterns; + x.t = x.toString; + switch (format) { + case "d": + return x.t(c.shortDate); + case "D": + return x.t(c.longDate); + case "F": + return x.t(c.fullDateTime); + case "m": + return x.t(c.monthDay); + case "r": + case "R": + y = x.clone().addMinutes(x.getTimezoneOffset()); + return y.toString(c.rfc1123) + " GMT"; + case "s": + return x.t(c.sortableDateTime); + case "t": + return x.t(c.shortTime); + case "T": + return x.t(c.longTime); + case "u": + y = x.clone().addMinutes(x.getTimezoneOffset()); + return y.toString(c.universalSortableDateTime); + case "y": + return x.t(c.yearMonth); + } + } + + return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, + function (m) { + if (m.charAt(0) === "\\") { + return m.replace("\\", ""); + } + x.h = x.getHours; + switch (m) { + case "hh": + return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12)); + case "h": + return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12); + case "HH": + return p(x.h()); + case "H": + return x.h(); + case "mm": + return p(x.getMinutes()); + case "m": + return x.getMinutes(); + case "ss": + return p(x.getSeconds()); + case "s": + return x.getSeconds(); + case "yyyy": + return p(x.getFullYear(), 4); + case "yy": + return p(x.getFullYear()); + case "dddd": + return Date.CultureInfo.dayNames[x.getDay()]; + case "ddd": + return Date.CultureInfo.abbreviatedDayNames[x.getDay()]; + case "dd": + return p(x.getDate()); + case "d": + return x.getDate(); + case "MMMM": + return Date.CultureInfo.monthNames[x.getMonth()]; + case "MMM": + return Date.CultureInfo.abbreviatedMonthNames[x.getMonth()]; + case "MM": + return p((x.getMonth() + 1)); + case "M": + return x.getMonth() + 1; + case "t": + return x.h() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1); + case "tt": + return x.h() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator; + case "S": + return ord(x.getDate()); + case "W": + return x.getWeek(); + case "WW": + return x.getISOWeek(); + case "Q": + return "Q" + x.getQuarter(); + case "q": + return String(x.getQuarter()); + default: + return m; + } + }).replace(/\[|\]/g, "") : this._toString(); + }; + +}()); + +(function () { + "use strict"; + Date.Parsing = { + Exception: function (s) { + this.message = "Parse error at '" + s.substring(0, 10) + " ...'"; + } + }; + var $P = Date.Parsing; + var dayOffsets = { + standard: [0,31,59,90,120,151,181,212,243,273,304,334], + leap: [0,31,60,91,121,152,182,213,244,274,305,335] + }; + + $P.isLeapYear = function(year) { + return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); + }; + + $P.processTimeObject = function (obj) { + var d, jan4, date, offset, dayOffset; + d = new Date(); + dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard; + obj.hours = obj.hours ? obj.hours : 0; + obj.minutes = obj.minutes ? obj.minutes : 0; + obj.seconds = obj.seconds ? obj.seconds : 0; + obj.milliseconds = obj.milliseconds ? obj.milliseconds : 0; + if (!obj.year) { + obj.year = d.getFullYear(); + } + if (!obj.month && (obj.week || obj.dayOfYear)) { + // work out the day of the year... + if (!obj.dayOfYear) { + obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay; + d = new Date(obj.year, 0, 4); + jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday. + offset = jan4+3; + obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset; + } + for (var i=0;i <= dayOffset.length;i++) { + if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) { + obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]); + break; + } else { + obj.month = i; + } + } + } else { + obj.month = obj.month ? obj.month : 0; + obj.day = obj.day ? obj.day : 1; + obj.dayOfYear = dayOffset[obj.month] + obj.day; + } + date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds); + + if (obj.zone) { + // adjust (and calculate) for timezone here + if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) { + // it's UTC/GML so work out the current timeszone offset + offset = -date.getTimezoneOffset(); + } else { + offset = (obj.zone_hours*60) + (obj.zone_minutes ? obj.zone_minutes : 0); + if (obj.zone_sign === "+") { + offset *= -1; + } + offset -= date.getTimezoneOffset(); + } + date.setMinutes(date.getMinutes()+offset); + } + return date; + }; + + $P.ISO = { + regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/, + parse : function (s) { + var data = s.match(this.regex); + if (!data || !data.length) { + return null; + } + var time = { + year : data[1] ? Number(data[1]) : data[1], + month : data[5] ? (Number(data[5])-1) : data[5], + day : data[7] ? Number(data[7]) : data[7], + week : data[8] ? Number(data[8]) : data[8], + weekDay : data[9] ? (Math.abs(Number(data[9])) === 7 ? 0 : Math.abs(Number(data[9]))) : data[9], // 1-7, starts on Monday. Convert to JS's 0-6 index. + dayOfYear : data[10] ? Number(data[10]) : data[10], + hours : data[15] ? Number(data[15]) : data[15], + minutes : data[16] ? Number(data[16].replace(":","")) : data[16], + seconds : data[19] ? Math.floor(Number(data[19].replace(":","").replace(",","."))) : data[19], + milliseconds : data[20] ? (Number(data[20].replace(",","."))*1000) : data[20], + zone : data[21], + zone_sign : data[22], + zone_hours : (data[23] && typeof data[23] !== "undefined") ? Number(data[23]) : data[23], + zone_minutes : (data[24] && typeof data[23] !== "undefined") ? Number(data[24]) : data[24] + }; + if (data[18]) { + data[18] = 60 * Number(data[18].replace(",", ".")); + if (!time.minutes) { + time.minutes = data[18]; + } else if (!time.seconds) { + time.seconds = data[18]; + } + } + if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) { + return null; + } + return $P.processTimeObject(time); + } + }; + $P.Numeric = { + isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e)}, + regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i, + parse: function (s) { + var data, i, + time = {}, + order = Date.CultureInfo.dateElementOrder.split(""); + if (!(this.isNumeric(s)) || // if it's non-numeric OR + (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000) + return null; + } + if (s.length < 5) { // assume it's just a year. + time.year = s; + return $P.processTimeObject(time); + } + data = s.match(this.regex); + if (!data || !data.length) { + return null; + } + for (i=0; i < order.length; i++) { + switch(order[i]) { + case "d": + time.day = data[i+1]; + break; + case "m": + time.month = (data[i+1]-1); + break; + case "y": + time.year = data[i+1]; + break; + } + } + return $P.processTimeObject(time); + } + }; + $P.Normalizer = { + parse: function (s) { + var $C = Date.CultureInfo; + var $R = Date.CultureInfo.regexPatterns; + var __ = Date.i18n.__; + + s = s.replace($R.jan.source, "January"); + s = s.replace($R.feb, "February"); + s = s.replace($R.mar, "March"); + s = s.replace($R.apr, "April"); + s = s.replace($R.may, "May"); + s = s.replace($R.jun, "June"); + s = s.replace($R.jul, "July"); + s = s.replace($R.aug, "August"); + s = s.replace($R.sep, "September"); + s = s.replace($R.oct, "October"); + s = s.replace($R.nov, "November"); + s = s.replace($R.dec, "December"); + + + s = s.replace($R.tomorrow, Date.today().addDays(1).toString("d")); + s = s.replace($R.yesterday, Date.today().addDays(-1).toString("d")); + // s = s.replace(new RegExp($R.today.source + "\\b", "i"), Date.today().toString("d")); + s = s.replace(/\bat\b/gi, ""); // replace "at", eg: "tomorrow at 3pm" + s = s.replace(/\s{2,}/, " "); // repliace multiple spaces with one. + + s = s.replace(new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"), function(full, m1, m2, m3, m4) { + var t = Date.today().addDays(1).toString("d"); + var s = t + " " + m1; + return s; + }); + + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.mon.source+'))'), Date.today().last().monday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.tue.source+'))'), Date.today().last().tuesday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.wed.source+'))'), Date.today().last().wednesday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.thu.source+'))'), Date.today().last().thursday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.fri.source+'))'), Date.today().last().friday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.sat.source+'))'), Date.today().last().saturday().toString("d")); + s = s.replace(new RegExp("(("+$R.past.source+')\\s('+$R.sun.source+'))'), Date.today().last().sunday().toString("d")); + + // s = s.replace($R.thisMorning, "9am")) + s = s.replace($R.amThisMorning, function(str, am){return am;}); + s = s.replace($R.inTheMorning, "am"); + s = s.replace($R.thisMorning, "9am"); + s = s.replace($R.amThisEvening, function(str, pm){return pm;}); + s = s.replace($R.inTheEvening, "pm"); + s = s.replace($R.thisEvening, "7pm"); + + try { + var n = s.split(/([\s\-\.\,\/\x27]+)/); + if (n.length === 3) { + if ($P.Numeric.isNumeric(n[0]) && $P.Numeric.isNumeric(n[2])) { + if (n[2].length >= 4) { + // ok, so we're dealing with x/year. But that's not a full date. + // This fixes wonky dateElementOrder parsing when set to dmy order. + if (Date.CultureInfo.dateElementOrder[0] === 'd') { + s = '1/' + n[0] + '/' + n[2]; // set to 1st of month and normalize the seperator + } + } + } + } + } catch (e) { + // continue... + } + + return s; + } + }; +}()); +(function () { + var $P = Date.Parsing; + var _ = $P.Operators = { + // + // Tokenizers + // + rtoken: function (r) { // regex token + return function (s) { + var mx = s.match(r); + if (mx) { + return ([ mx[0], s.substring(mx[0].length) ]); + } else { + throw new $P.Exception(s); + } + }; + }, + token: function (s) { // whitespace-eating token + return function (s) { + return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s); + // Removed .strip() + // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip(); + }; + }, + stoken: function (s) { // string token + return _.rtoken(new RegExp("^" + s)); + }, + + // + // Atomic Operators + // + + until: function (p) { + return function (s) { + var qx = [], rx = null; + while (s.length) { + try { + rx = p.call(this, s); + } catch (e) { + qx.push(rx[0]); + s = rx[1]; + continue; + } + break; + } + return [ qx, s ]; + }; + }, + many: function (p) { + return function (s) { + var rx = [], r = null; + while (s.length) { + try { + r = p.call(this, s); + } catch (e) { + return [ rx, s ]; + } + rx.push(r[0]); + s = r[1]; + } + return [ rx, s ]; + }; + }, + + // generator operators -- see below + optional: function (p) { + return function (s) { + var r = null; + try { + r = p.call(this, s); + } catch (e) { + return [ null, s ]; + } + return [ r[0], r[1] ]; + }; + }, + not: function (p) { + return function (s) { + try { + p.call(this, s); + } catch (e) { + return [null, s]; + } + throw new $P.Exception(s); + }; + }, + ignore: function (p) { + return p ? + function (s) { + var r = null; + r = p.call(this, s); + return [null, r[1]]; + } : null; + }, + product: function () { + var px = arguments[0], + qx = Array.prototype.slice.call(arguments, 1), rx = []; + for (var i = 0 ; i < px.length ; i++) { + rx.push(_.each(px[i], qx)); + } + return rx; + }, + cache: function (rule) { + var cache = {}, r = null; + return function (s) { + try { + r = cache[s] = (cache[s] || rule.call(this, s)); + } catch (e) { + r = cache[s] = e; + } + if (r instanceof $P.Exception) { + throw r; + } else { + return r; + } + }; + }, + + // vector operators -- see below + any: function () { + var px = arguments; + return function (s) { + var r = null; + for (var i = 0; i < px.length; i++) { + if (px[i] == null) { + continue; + } + try { + r = (px[i].call(this, s)); + } catch (e) { + r = null; + } + if (r) { + return r; + } + } + throw new $P.Exception(s); + }; + }, + each: function () { + var px = arguments; + return function (s) { + var rx = [], r = null; + for (var i = 0; i < px.length ; i++) { + if (px[i] == null) { + continue; + } + try { + r = (px[i].call(this, s)); + } catch (e) { + throw new $P.Exception(s); + } + rx.push(r[0]); + s = r[1]; + } + return [ rx, s]; + }; + }, + all: function () { + var px = arguments, _ = _; + return _.each(_.optional(px)); + }, + + // delimited operators + sequence: function (px, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + + if (px.length == 1) { + return px[0]; + } + return function (s) { + var r = null, q = null; + var rx = []; + for (var i = 0; i < px.length ; i++) { + try { + r = px[i].call(this, s); + } catch (e) { + break; + } + rx.push(r[0]); + try { + q = d.call(this, r[1]); + } catch (ex) { + q = null; + break; + } + s = q[1]; + } + if (!r) { + throw new $P.Exception(s); + } + if (q) { + throw new $P.Exception(q[1]); + } + if (c) { + try { + r = c.call(this, r[1]); + } catch (ey) { + throw new $P.Exception(r[1]); + } + } + return [ rx, (r?r[1]:s) ]; + }; + }, + + // + // Composite Operators + // + + between: function (d1, p, d2) { + d2 = d2 || d1; + var _fn = _.each(_.ignore(d1), p, _.ignore(d2)); + return function (s) { + var rx = _fn.call(this, s); + return [[rx[0][0], r[0][2]], rx[1]]; + }; + }, + list: function (p, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + return (p instanceof Array ? + _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) : + _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c))); + }, + set: function (px, d, c) { + d = d || _.rtoken(/^\s*/); + c = c || null; + return function (s) { + // r is the current match, best the current 'best' match + // which means it parsed the most amount of input + var r = null, p = null, q = null, rx = null, best = [[], s], last = false; + // go through the rules in the given set + for (var i = 0; i < px.length ; i++) { + + // last is a flag indicating whether this must be the last element + // if there is only 1 element, then it MUST be the last one + q = null; + p = null; + r = null; + last = (px.length == 1); + + // first, we try simply to match the current pattern + // if not, try the next pattern + try { + r = px[i].call(this, s); + } catch (e) { + continue; + } + // since we are matching against a set of elements, the first + // thing to do is to add r[0] to matched elements + rx = [[r[0]], r[1]]; + // if we matched and there is still input to parse and + // we don't already know this is the last element, + // we're going to next check for the delimiter ... + // if there's none, or if there's no input left to parse + // than this must be the last element after all ... + if (r[1].length > 0 && ! last) { + try { + q = d.call(this, r[1]); + } catch (ex) { + last = true; + } + } else { + last = true; + } + + // if we parsed the delimiter and now there's no more input, + // that means we shouldn't have parsed the delimiter at all + // so don't update r and mark this as the last element ... + if (!last && q[1].length === 0) { + last = true; + } + + + // so, if this isn't the last element, we're going to see if + // we can get any more matches from the remaining (unmatched) + // elements ... + if (!last) { + // build a list of the remaining rules we can match against, + // i.e., all but the one we just matched against + var qx = []; + for (var j = 0; j < px.length ; j++) { + if (i != j) { + qx.push(px[j]); + } + } + + // now invoke recursively set with the remaining input + // note that we don't include the closing delimiter ... + // we'll check for that ourselves at the end + p = _.set(qx, d).call(this, q[1]); + + // if we got a non-empty set as a result ... + // (otw rx already contains everything we want to match) + if (p[0].length > 0) { + // update current result, which is stored in rx ... + // basically, pick up the remaining text from p[1] + // and concat the result from p[0] so that we don't + // get endless nesting ... + rx[0] = rx[0].concat(p[0]); + rx[1] = p[1]; + } + } + + // at this point, rx either contains the last matched element + // or the entire matched set that starts with this element. + + // now we just check to see if this variation is better than + // our best so far, in terms of how much of the input is parsed + if (rx[1].length < best[1].length) { + best = rx; + } + + // if we've parsed all the input, then we're finished + if (best[1].length === 0) { + break; + } + } + + // so now we've either gone through all the patterns trying them + // as the initial match; or we found one that parsed the entire + // input string ... + + // if best has no matches, just return empty set ... + if (best[0].length === 0) { + return best; + } + + // if a closing delimiter is provided, then we have to check it also + if (c) { + // we try this even if there is no remaining input because the pattern + // may well be optional or match empty input ... + try { + q = c.call(this, best[1]); + } catch (ey) { + throw new $P.Exception(best[1]); + } + + // it parsed ... be sure to update the best match remaining input + best[1] = q[1]; + } + // if we're here, either there was no closing delimiter or we parsed it + // so now we have the best match; just return it! + return best; + }; + }, + forward: function (gr, fname) { + return function (s) { + return gr[fname].call(this, s); + }; + }, + + // + // Translation Operators + // + replace: function (rule, repl) { + return function (s) { + var r = rule.call(this, s); + return [repl, r[1]]; + }; + }, + process: function (rule, fn) { + return function (s) { + var r = rule.call(this, s); + return [fn.call(this, r[0]), r[1]]; + }; + }, + min: function (min, rule) { + return function (s) { + var rx = rule.call(this, s); + if (rx[0].length < min) { + throw new $P.Exception(s); + } + return rx; + }; + } + }; + + + // Generator Operators And Vector Operators + + // Generators are operators that have a signature of F(R) => R, + // taking a given rule and returning another rule, such as + // ignore, which parses a given rule and throws away the result. + + // Vector operators are those that have a signature of F(R1,R2,...) => R, + // take a list of rules and returning a new rule, such as each. + + // Generator operators are converted (via the following _generator + // function) into functions that can also take a list or array of rules + // and return an array of new rules as though the function had been + // called on each rule in turn (which is what actually happens). + + // This allows generators to be used with vector operators more easily. + // Example: + // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar)) + + // This also turns generators into vector operators, which allows + // constructs like: + // not(cache(foo, bar)) + + var _generator = function (op) { + function gen() { + var args = null, rx = [], px, i; + if (arguments.length > 1) { + args = Array.prototype.slice.call(arguments); + } else if (arguments[0] instanceof Array) { + args = arguments[0]; + } + if (args) { + px = args.shift(); + if (px.length > 0) { + args.unshift(px[i]); + rx.push(op.apply(null, args)); + args.shift(); + return rx; + } + } else { + return op.apply(null, arguments); + } + } + + return gen; + }; + + var gx = "optional not ignore cache".split(/\s/); + + for (var i = 0 ; i < gx.length ; i++) { + _[gx[i]] = _generator(_[gx[i]]); + } + + var _vector = function (op) { + return function () { + if (arguments[0] instanceof Array) { + return op.apply(null, arguments[0]); + } else { + return op.apply(null, arguments); + } + }; + }; + + var vx = "each any all".split(/\s/); + + for (var j = 0 ; j < vx.length ; j++) { + _[vx[j]] = _vector(_[vx[j]]); + } + +}()); + +(function () { + var $D = Date; + + var flattenAndCompact = function (ax) { + var rx = []; + for (var i = 0; i < ax.length; i++) { + if (ax[i] instanceof Array) { + rx = rx.concat(flattenAndCompact(ax[i])); + } else { + if (ax[i]) { + rx.push(ax[i]); + } + } + } + return rx; + }; + + $D.Grammar = {}; + + $D.Translator = { + hour: function (s) { + return function () { + this.hour = Number(s); + }; + }, + minute: function (s) { + return function () { + this.minute = Number(s); + }; + }, + second: function (s) { + return function () { + this.second = Number(s); + }; + }, + /* for ss.s format */ + secondAndMillisecond: function (s) { + return function () { + var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/); + this.second = Number(mx[1]); + this.millisecond = Number(mx[2]); + }; + }, + meridian: function (s) { + return function () { + this.meridian = s.slice(0, 1).toLowerCase(); + }; + }, + timezone: function (s) { + return function () { + var n = s.replace(/[^\d\+\-]/g, ""); + if (n.length) { + this.timezoneOffset = Number(n); + } else { + this.timezone = s.toLowerCase(); + } + }; + }, + day: function (x) { + var s = x[0]; + return function () { + this.day = Number(s.match(/\d+/)[0]); + if (this.day < 1) { + throw "invalid day"; + } + }; + }, + month: function (s) { + return function () { + this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1; + if (this.month < 0) { + throw "invalid month"; + } + }; + }, + year: function (s) { + return function () { + var n = Number(s); + this.year = ((s.length > 2) ? n : + (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900))); + }; + }, + rday: function (s) { + return function () { + switch (s) { + case "yesterday": + this.days = -1; + break; + case "tomorrow": + this.days = 1; + break; + case "today": + this.days = 0; + break; + case "now": + this.days = 0; + this.now = true; + break; + } + }; + }, + finishExact: function (x) { + x = (x instanceof Array) ? x : [ x ]; + + for (var i = 0 ; i < x.length ; i++) { + if (x[i]) { + x[i].call(this); + } + } + + var now = new Date(); + if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) { + this.day = now.getDate(); + } + + if (!this.year) { + this.year = now.getFullYear(); + } + + if (!this.month && this.month !== 0) { + this.month = now.getMonth(); + } + + if (!this.day) { + this.day = 1; + } + + if (!this.hour) { + this.hour = 0; + } + + if (!this.minute) { + this.minute = 0; + } + + if (!this.second) { + this.second = 0; + } + if (!this.millisecond) { + this.millisecond = 0; + } + + if (this.meridian && (this.hour || this.hour === 0)) { + if (this.meridian == "a" && this.hour > 11 && Date.Config.strict24hr){ + throw "Invalid hour and meridian combination"; + } else if (this.meridian == "p" && this.hour < 12 && Date.Config.strict24hr){ + throw "Invalid hour and meridian combination"; + } else if (this.meridian == "p" && this.hour < 12) { + this.hour = this.hour + 12; + } else if (this.meridian == "a" && this.hour == 12) { + this.hour = 0; + } + } + + if (this.day > $D.getDaysInMonth(this.year, this.month)) { + throw new RangeError(this.day + " is not a valid value for days."); + } + + var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + if (this.year < 100) { + r.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999. + } + if (this.timezone) { + r.set({ timezone: this.timezone }); + } else if (this.timezoneOffset) { + r.set({ timezoneOffset: this.timezoneOffset }); + } + + return r; + }, + finish: function (x) { + x = (x instanceof Array) ? flattenAndCompact(x) : [ x ]; + + if (x.length === 0) { + return null; + } + + for (var i = 0 ; i < x.length ; i++) { + if (typeof x[i] == "function") { + x[i].call(this); + } + } + + var today = $D.today(); + + if (this.now && !this.unit && !this.operator) { + return new Date(); + } else if (this.now) { + today = new Date(); + } + + var expression = !!(this.days && this.days !== null || this.orient || this.operator); + + var gap, mod, orient; + orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1); + + if(!this.now && "hour minute second".indexOf(this.unit) != -1) { + today.setTimeToNow(); + } + + if (this.month && this.unit == "week") { + this.value = this.month + 1; + delete this.month; + delete this.day; + } + + if (this.month || this.month === 0) { + if ("year day hour minute second".indexOf(this.unit) != -1) { + if (!this.value) { + this.value = this.month + 1; + } + this.month = null; + expression = true; + } + } + + if (!expression && this.weekday && !this.day && !this.days) { + var temp = Date[this.weekday](); + this.day = temp.getDate(); + if (!this.month) { + this.month = temp.getMonth(); + } + this.year = temp.getFullYear(); + } + + if (expression && this.weekday && this.unit != "month" && this.unit != "week") { + this.unit = "day"; + gap = ($D.getDayNumberFromName(this.weekday) - today.getDay()); + mod = 7; + this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); + } + + if (this.month && this.unit == "day" && this.operator) { + if (!this.value) { + this.value = (this.month + 1); + } + this.month = null; + } + + if (this.value != null && this.month != null && this.year != null) { + this.day = this.value * 1; + } + + if (this.month && !this.day && this.value) { + today.set({ day: this.value * 1 }); + if (!expression) { + this.day = this.value * 1; + } + } + + if (!this.month && this.value && this.unit == "month" && !this.now) { + this.month = this.value; + expression = true; + } + + if (expression && (this.month || this.month === 0) && this.unit != "year") { + this.unit = "month"; + gap = (this.month - today.getMonth()); + mod = 12; + this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod); + this.month = null; + } + + if (!this.unit) { + this.unit = "day"; + } + + if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) { + this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient; + } else if (this[this.unit + "s"] == null || this.operator != null) { + if (!this.value) { + this.value = 1; + } + this[this.unit + "s"] = this.value * orient; + } + + if (this.meridian && (this.hour || this.hour === 0)) { + if (this.meridian == "a" && this.hour > 11 && Date.Config.strict24hr){ + throw "Invalid hour and meridian combination"; + } else if (this.meridian == "p" && this.hour < 12 && Date.Config.strict24hr){ + throw "Invalid hour and meridian combination"; + } else if (this.meridian == "p" && this.hour < 12) { + this.hour = this.hour + 12; + } else if (this.meridian == "a" && this.hour == 12) { + this.hour = 0; + } + } + + if (this.weekday && this.unit !== "week" && !this.day && !this.days) { + var temp = Date[this.weekday](); + this.day = temp.getDate(); + if (temp.getMonth() !== today.getMonth()) { + this.month = temp.getMonth(); + } + } + + if ((this.month || this.month === 0) && !this.day) { + this.day = 1; + } + + if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) { + return Date.today().setWeek(this.value); + } + + if (this.unit == "week" && this.weeks && !this.day && !this.month) { + var weekday = (this.weekday) ? this.weekday : "today"; + var d = Date[weekday]().addWeeks(this.weeks); + if (this.now) { + d.setTimeToNow(); + } + return d; + } + + if (expression && this.timezone && this.day && this.days) { + this.day = this.days; + } + + return (expression) ? today.add(this) : today.set(this); + } + }; + + var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn; + + g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/); + g.timePartDelimiter = _.stoken(":"); + g.whiteSpace = _.rtoken(/^\s*/); + g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/); + + var _C = {}; + g.ctoken = function (keys) { + var fn = _C[keys]; + if (! fn) { + var c = Date.CultureInfo.regexPatterns; + var kx = keys.split(/\s+/), px = []; + for (var i = 0; i < kx.length ; i++) { + px.push(_.replace(_.rtoken(c[kx[i]]), kx[i])); + } + fn = _C[keys] = _.any.apply(null, px); + } + return fn; + }; + g.ctoken2 = function (key) { + return _.rtoken(Date.CultureInfo.regexPatterns[key]); + }; + + // hour, minute, second, meridian, timezone + g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour)); + g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour)); + g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour)); + g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour)); + g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute)); + g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute)); + g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second)); + g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second)); + g["ss.s"] = _.cache(_.process(_.rtoken(/^[0-5][0-9]\.[0-9]{1,3}/), t.secondAndMillisecond)); + g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter)); + + // _.min(1, _.set([ g.H, g.m, g.s ], g._t)); + g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian)); + g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian)); + g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone)); + g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone)); + + g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone)); + g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ])); + g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix); + + // days, months, years + g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/), + _.optional(g.ctoken2("ordinalSuffix"))), t.day)); + g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/), + _.optional(g.ctoken2("ordinalSuffix"))), t.day)); + g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"), + function (s) { + return function () { + this.weekday = s; + }; + } + )); + g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month)); + g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month)); + g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month)); +// g.MMM = g.MMMM = _.cache(_.process(g.ctoken(Date.CultureInfo.abbreviatedMonthNames.join(" ")), t.month)); + g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year)); + g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year)); + g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year)); + g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year)); + + // rolling these up into general purpose rules + _fn = function () { + return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext"))); + }; + + g.day = _fn(g.d, g.dd); + g.month = _fn(g.M, g.MMM); + g.year = _fn(g.yyyy, g.yy); + + // relative date / time expressions + g.orientation = _.process(g.ctoken("past future"), + function (s) { + return function () { + this.orient = s; + }; + } + ); + g.operator = _.process(g.ctoken("add subtract"), + function (s) { + return function () { + this.operator = s; + }; + } + ); + g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday); + g.unit = _.process(g.ctoken("second minute hour day week month year"), + function (s) { + return function () { + this.unit = s; + }; + } + ); + g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/), + function (s) { + return function () { + this.value = s.replace(/\D/g, ""); + }; + } + ); + g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]); + + // pre-loaded rules for different date part order preferences + _fn = function () { + return _.set(arguments, g.datePartDelimiter); + }; + g.mdy = _fn(g.ddd, g.month, g.day, g.year); + g.ymd = _fn(g.ddd, g.year, g.month, g.day); + g.dmy = _fn(g.ddd, g.day, g.month, g.year); + g.date = function (s) { + return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s)); + }; + + // parsing date format specifiers - ex: "h:m:s tt" + // this little guy will generate a custom parser based + // on the format string, ex: g.format("h:m:s tt") + g.format = _.process(_.many( + _.any( + // translate format specifiers into grammar rules + _.process( + _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/), + function (fmt) { + if (g[fmt]) { + return g[fmt]; + } else { + throw $D.Parsing.Exception(fmt); + } + } + ), + // translate separator tokens into token rules + _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators + function (s) { + return _.ignore(_.stoken(s)); + } + ) + )), + // construct the parser ... + function (rules) { + return _.process(_.each.apply(null, rules), t.finishExact); + } + ); + + var _F = { + //"M/d/yyyy": function (s) { + // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/); + // if (m!=null) { + // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ]; + // r = t.finishExact.call(this,r); + // return [ r, "" ]; + // } else { + // throw new Date.Parsing.Exception(s); + // } + //} + //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; } + }; + var _get = function (f) { + _F[f] = (_F[f] || g.format(f)[0]); + return _F[f]; + }; + + g.allformats = function (fx) { + var rx = []; + if (fx instanceof Array) { + for (var i = 0; i < fx.length; i++) { + rx.push(_get(fx[i])); + } + } else { + rx.push(_get(fx)); + } + return rx; + }; + + g.formats = function (fx) { + if (fx instanceof Array) { + var rx = []; + for (var i = 0 ; i < fx.length ; i++) { + rx.push(_get(fx[i])); + } + return _.any.apply(null, rx); + } else { + return _get(fx); + } + }; + + // check for these formats first + g._formats = g.formats([ + "\"yyyy-MM-ddTHH:mm:ssZ\"", + "yyyy-MM-ddTHH:mm:ss.sz", + "yyyy-MM-ddTHH:mm:ssZ", + "yyyy-MM-ddTHH:mm:ssz", + "yyyy-MM-ddTHH:mm:ss", + "yyyy-MM-ddTHH:mmZ", + "yyyy-MM-ddTHH:mmz", + "yyyy-MM-ddTHH:mm", + "ddd, MMM dd, yyyy H:mm:ss tt", + "ddd MMM d yyyy HH:mm:ss zzz", + "MMddyyyy", + "ddMMyyyy", + "Mddyyyy", + "ddMyyyy", + "Mdyyyy", + "dMyyyy", + "yyyy", + "Mdyy", + "dMyy", + "d" + ]); + + // starting rule for general purpose grammar + g._start = _.process(_.set([ g.date, g.time, g.expression ], + g.generalDelimiter, g.whiteSpace), t.finish); + + // real starting rule: tries selected formats first, + // then general purpose rule + g.start = function (s) { + try { + var r = g._formats.call({}, s); + if (r[1].length === 0) { + return r; + } + } catch (e) {} + return g._start.call({}, s); + }; + + /** + * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information. + * + * Example +
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ function parse (s) {
+ var ords, d, t, r = null;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ s = $D.Parsing.Normalizer.parse(s);
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+ d = ((r[1].length === 0) ? r[0] : null);
+
+ if (d !== null) {
+ return d;
+ } else {
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+ for (var i = 0; i < dx.length; i++) {
+ // Create constant static Day Name variables. Example: Date.MONDAY or Date.MON
+ $D[dx[i].toUpperCase()] = $D[dx[i].toUpperCase().substring(0, 3)] = i;
+
+ // Create Day Name functions. Example: Date.monday() or Date.mon()
+ $D[dx[i]] = $D[dx[i].substring(0, 3)] = sdf(i);
+
+ // Create Day Name instance functions. Example: Date.today().next().monday()
+ $P[dx[i]] = $P[dx[i].substring(0, 3)] = df(i);
+ }
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ for (var j = 0; j < mx.length; j++) {
+ // Create constant static Month Name variables. Example: Date.MARCH or Date.MAR
+ $D[mx[j].toUpperCase()] = $D[mx[j].toUpperCase().substring(0, 3)] = j;
+
+ // Create Month Name functions. Example: Date.march() or Date.mar()
+ $D[mx[j]] = $D[mx[j].substring(0, 3)] = month_static_functions(j);
+
+ // Create Month Name instance functions. Example: Date.today().next().march()
+ $P[mx[j]] = $P[mx[j].substring(0, 3)] = month_instance_functions(j);
+ }
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ $f = [],
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with .$format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ + var f1 = "%m/%d/%y" + var f2 = Date.normalizeFormat(f1); // "MM/dd/yy" + + new Date().format(f1); // "04/13/08" + new Date().$format(f1); // "04/13/08" + new Date().toString(f2); // "04/13/08" + + var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008 ++ * @param {String} A PHP format string consisting of one or more format spcifiers. + * @return {String} The PHP format converted to a Java/.NET format string. + */ + $D.normalizeFormat = function (format) { + // function does nothing atm + // $f = []; + // var t = new Date().$format(format); + // return $f.join(""); + return format; + }; + /** + * Format a local Unix timestamp according to locale settings + * + * Example +
+ Date.strftime("%m/%d/%y", new Date()); // "04/13/08" + Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08" ++ * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @param {Number} The number representing the number of seconds that have elapsed since January 1, 1970 (local time). + * @return {String} A string representation of the current Date object. + */ + $D.strftime = function (format, time) { + return new Date(time * 1000).$format(format); + }; + /** + * Parse any textual datetime description into a Unix timestamp. + * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT). + * + * Example +
+ Date.strtotime("04/13/08"); // 1208044800 + Date.strtotime("1970-01-01T00:00:00Z"); // 0 ++ * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @param {Object} A string or date object. + * @return {String} A string representation of the current Date object. + */ + $D.strtotime = function (time) { + var d = $D.parse(time); + d.addMinutes(d.getTimezoneOffset() * -1); + return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000); + }; + /** + * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers. + * + * The following descriptions are from http://www.php.net/strftime and http://www.php.net/manual/en/function.date.php. + * Copyright � 2001-2008 The PHP Group + * + * Format Specifiers +
+ Format Description Example + ------ --------------------------------------------------------------------------- ----------------------- + %a abbreviated weekday name according to the current localed "Mon" through "Sun" + %A full weekday name according to the current locale "Sunday" through "Saturday" + %b abbreviated month name according to the current locale "Jan" through "Dec" + %B full month name according to the current locale "January" through "December" + %c preferred date and time representation for the current locale "4/13/2008 12:33 PM" + %C century number (the year divided by 100 and truncated to an integer) "00" to "99" + %d day of the month as a decimal number "01" to "31" + %D same as %m/%d/%y "04/13/08" + %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31" + %g like %G, but without the century "08" + %G The 4-digit year corresponding to the ISO week number (see %V). "2008" + This has the same format and value as %Y, except that if the ISO week number + belongs to the previous or next year, that year is used instead. + %h same as %b "Jan" through "Dec" + %H hour as a decimal number using a 24-hour clock "00" to "23" + %I hour as a decimal number using a 12-hour clock "01" to "12" + %j day of the year as a decimal number "001" to "366" + %m month as a decimal number "01" to "12" + %M minute as a decimal number "00" to "59" + %n newline character "\n" + %p either "am" or "pm" according to the given time value, or the "am" or "pm" + corresponding strings for the current locale + %r time in a.m. and p.m. notation "8:44 PM" + %R time in 24 hour notation "20:44" + %S second as a decimal number "00" to "59" + %t tab character "\t" + %T current time, equal to %H:%M:%S "12:49:11" + %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7" + %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53") + first Sunday as the first day of the first week + %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53") + range 01 to 53, where week 1 is the first week that has at least 4 days + in the current year, and with Monday as the first day of the week. + (Use %G or %g for the year component that corresponds to the week number + for the specified timestamp.) + %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53") + first Monday as the first day of the first week + %w day of the week as a decimal, Sunday being "0" "0" to "6" + %x preferred date representation for the current locale without the time "4/13/2008" + %X preferred time representation for the current locale without the date "12:53:05" + %y year as a decimal number without a century "00" "99" + %Y year as a decimal number including the century "2008" + %Z time zone or name or abbreviation "UTC", "EST", "PST" + %z same as %Z + %% a literal "%" character "%" + d Day of the month, 2 digits with leading zeros "01" to "31" + D A textual representation of a day, three letters "Mon" through "Sun" + j Day of the month without leading zeros "1" to "31" + l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday" + N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday) + S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j + w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday) + z The day of the year (starting from "0") "0" through "365" + W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53") + F A full textual representation of a month, such as January or March "January" through "December" + m Numeric representation of a month, with leading zeros "01" through "12" + M A short textual representation of a month, three letters "Jan" through "Dec" + n Numeric representation of a month, without leading zeros "1" through "12" + t Number of days in the given month "28" through "31" + L Whether it's a leap year "1" if it is a leap year, "0" otherwise + o ISO-8601 year number. This has the same value as Y, except that if the "2008" + ISO week number (W) belongs to the previous or next year, that year + is used instead. + Y A full numeric representation of a year, 4 digits "2008" + y A two digit representation of a year "08" + a Lowercase Ante meridiem and Post meridiem "am" or "pm" + A Uppercase Ante meridiem and Post meridiem "AM" or "PM" + B Swatch Internet time "000" through "999" + g 12-hour format of an hour without leading zeros "1" through "12" + G 24-hour format of an hour without leading zeros "0" through "23" + h 12-hour format of an hour with leading zeros "01" through "12" + H 24-hour format of an hour with leading zeros "00" through "23" + i Minutes with leading zeros "00" to "59" + s Seconds, with leading zeros "00" through "59" + u Milliseconds "54321" + e Timezone identifier "UTC", "EST", "PST" + I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise + O Difference to Greenwich time (GMT) in hours "+0200", "-0600" + P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00" + T Timezone abbreviation "UTC", "EST", "PST" + Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400" + always negative, and for those east of UTC is always positive. + c ISO 8601 date "2004-02-12T15:19:21+00:00" + r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200" + U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0" ++ * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @return {String} A string representation of the current Date object. + */ + $P.$format = function (format) { + var x = this, y, + t = function (v, overrideStandardFormats) { + $f.push(v); + return x.toString(v, overrideStandardFormats); + }; + return format ? format.replace(/(%|\\)?.|%%/g, + function (m) { + if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") { + return m.replace("\\", "").replace("%%", "%"); + } + switch (m) { + case "d": + case "%d": + return t("dd"); + case "D": + case "%a": + return t("ddd"); + case "j": + case "%e": + return t("d", true); + case "l": + case "%A": + return t("dddd"); + case "N": + case "%u": + return x.getDay() + 1; + case "S": + return t("S"); + case "w": + case "%w": + return x.getDay(); + case "z": + return x.getOrdinalNumber(); + case "%j": + return p(x.getOrdinalNumber(), 3); + case "%U": + var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0), + d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1); + return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1); + case "W": + case "%V": + return x.getISOWeek(); + case "%W": + return p(x.getWeek()); + case "F": + case "%B": + return t("MMMM"); + case "m": + case "%m": + return t("MM"); + case "M": + case "%b": + case "%h": + return t("MMM"); + case "n": + return t("M"); + case "t": + return $D.getDaysInMonth(x.getFullYear(), x.getMonth()); + case "L": + return ($D.isLeapYear(x.getFullYear())) ? 1 : 0; + case "o": + case "%G": + return x.setWeek(x.getISOWeek()).toString("yyyy"); + case "%g": + return x.$format("%G").slice(-2); + case "Y": + case "%Y": + return t("yyyy"); + case "y": + case "%y": + return t("yy"); + case "a": + case "%p": + return t("tt").toLowerCase(); + case "A": + return t("tt").toUpperCase(); + case "g": + case "%I": + return t("h"); + case "G": + return t("H"); + case "h": + return t("hh"); + case "H": + case "%H": + return t("HH"); + case "i": + case "%M": + return t("mm"); + case "s": + case "%S": + return t("ss"); + case "u": + return p(x.getMilliseconds(), 3); + case "I": + return (x.isDaylightSavingTime()) ? 1 : 0; + case "O": + return x.getUTCOffset(); + case "P": + y = x.getUTCOffset(); + return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2); + case "e": + case "T": + case "%z": + case "%Z": + return x.getTimezone(); + case "Z": + return x.getTimezoneOffset() * -60; + case "B": + var now = new Date(); + return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4); + case "c": + return x.toISOString().replace(/\"/g, ""); + case "U": + return $D.strtotime("now"); + case "%c": + return t("d") + " " + t("t"); + case "%C": + return Math.floor(x.getFullYear() / 100 + 1); + case "%D": + return t("MM/dd/yy"); + case "%n": + return "\\n"; + case "%t": + return "\\t"; + case "%r": + return t("hh:mm tt"); + case "%R": + return t("H:mm"); + case "%T": + return t("H:mm:ss"); + case "%x": + return t("d"); + case "%X": + return t("t"); + default: + $f.push(m); + return m; + } + }) : this._toString(); + }; + + if (!$P.format) { + $P.format = $P.$format; + } +}()); +/* + * TimeSpan(milliseconds); + * TimeSpan(days, hours, minutes, seconds); + * TimeSpan(days, hours, minutes, seconds, milliseconds); + */ +var TimeSpan = function (days, hours, minutes, seconds, milliseconds) { + var attrs = "days hours minutes seconds milliseconds".split(/\s+/); + + var gFn = function (attr) { + return function () { + return this[attr]; + }; + }; + + var sFn = function (attr) { + return function (val) { + this[attr] = val; + return this; + }; + }; + + for (var i = 0; i < attrs.length ; i++) { + var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1); + TimeSpan.prototype[$a] = 0; + TimeSpan.prototype["get" + $b] = gFn($a); + TimeSpan.prototype["set" + $b] = sFn($a); + } + + if (arguments.length === 4) { + this.setDays(days); + this.setHours(hours); + this.setMinutes(minutes); + this.setSeconds(seconds); + } else if (arguments.length === 5) { + this.setDays(days); + this.setHours(hours); + this.setMinutes(minutes); + this.setSeconds(seconds); + this.setMilliseconds(milliseconds); + } else if (arguments.length === 1 && typeof days === "number") { + var orient = (days < 0) ? -1 : +1; + this.setMilliseconds(Math.abs(days)); + + this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient); + this.setMilliseconds(this.getMilliseconds() % 86400000); + + this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient); + this.setMilliseconds(this.getMilliseconds() % 3600000); + + this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient); + this.setMilliseconds(this.getMilliseconds() % 60000); + + this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient); + this.setMilliseconds(this.getMilliseconds() % 1000); + + this.setMilliseconds(this.getMilliseconds() * orient); + } + + this.getTotalMilliseconds = function () { + return (this.getDays() * 86400000) + + (this.getHours() * 3600000) + + (this.getMinutes() * 60000) + + (this.getSeconds() * 1000); + }; + + this.compareTo = function (time) { + var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2; + if (time === null) { + t2 = new Date(1970, 1, 1, 0, 0, 0); + } + else { + t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds()); + } + return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0; + }; + + this.equals = function (time) { + return (this.compareTo(time) === 0); + }; + + this.add = function (time) { + return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000); + }; + + this.subtract = function (time) { + return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000); + }; + + this.addDays = function (n) { + return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000)); + }; + + this.addHours = function (n) { + return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000)); + }; + + this.addMinutes = function (n) { + return new TimeSpan(this.getTotalMilliseconds() + (n * 60000)); + }; + + this.addSeconds = function (n) { + return new TimeSpan(this.getTotalMilliseconds() + (n * 1000)); + }; + + this.addMilliseconds = function (n) { + return new TimeSpan(this.getTotalMilliseconds() + n); + }; + + this.get12HourHour = function () { + return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours(); + }; + + this.getDesignator = function () { + return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator; + }; + + this.toString = function (format) { + this._toString = function () { + if (this.getDays() !== null && this.getDays() > 0) { + return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds()); + } else { + return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds()); + } + }; + + this.p = function (s) { + return (s.toString().length < 2) ? "0" + s : s; + }; + + var me = this; + + return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g, + function (format) { + switch (format) { + case "d": + return me.getDays(); + case "dd": + return me.p(me.getDays()); + case "H": + return me.getHours(); + case "HH": + return me.p(me.getHours()); + case "h": + return me.get12HourHour(); + case "hh": + return me.p(me.get12HourHour()); + case "m": + return me.getMinutes(); + case "mm": + return me.p(me.getMinutes()); + case "s": + return me.getSeconds(); + case "ss": + return me.p(me.getSeconds()); + case "t": + return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1); + case "tt": + return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator; + } + } + ) : this._toString(); + }; + return this; +}; + +/** + * Gets the time of day for this date instances. + * @return {TimeSpan} TimeSpan + */ +Date.prototype.getTimeOfDay = function () { + return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds()); +}; + +/* + * TimePeriod(startDate, endDate); + * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds); + */ +var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) { + var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/); + + var gFn = function (attr) { + return function () { + return this[attr]; + }; + }; + + var sFn = function (attr) { + return function (val) { + this[attr] = val; + return this; + }; + }; + + for (var i = 0; i < attrs.length ; i++) { + var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1); + TimePeriod.prototype[$a] = 0; + TimePeriod.prototype["get" + $b] = gFn($a); + TimePeriod.prototype["set" + $b] = sFn($a); + } + + if (arguments.length === 7) { + this.years = years; + this.months = months; + this.setDays(days); + this.setHours(hours); + this.setMinutes(minutes); + this.setSeconds(seconds); + this.setMilliseconds(milliseconds); + } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) { + // startDate and endDate as arguments + + var d1 = years.clone(); + var d2 = months.clone(); + + var temp = d1.clone(); + var orient = (d1 > d2) ? -1 : +1; + + this.years = d2.getFullYear() - d1.getFullYear(); + temp.addYears(this.years); + + if (orient === +1) { + if (temp > d2) { + if (this.years !== 0) { + this.years--; + } + } + } else { + if (temp < d2) { + if (this.years !== 0) { + this.years++; + } + } + } + + d1.addYears(this.years); + + if (orient === +1) { + while (d1 < d2 && d1.clone().addMonths(1) <= d2) { + d1.addMonths(1); + this.months++; + } + } + else { + while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) { + d1.addMonths(-1); + this.months--; + } + } + + var diff = d2 - d1; + + if (diff !== 0) { + var ts = new TimeSpan(diff); + this.setDays(ts.getDays()); + this.setHours(ts.getHours()); + this.setMinutes(ts.getMinutes()); + this.setSeconds(ts.getSeconds()); + this.setMilliseconds(ts.getMilliseconds()); + } + } + return this; +}; \ No newline at end of file diff --git a/vendors/DateJS/build/date-en-ZA.js b/vendors/DateJS/build/date-en-ZA.js new file mode 100644 index 0000000..34f2523 --- /dev/null +++ b/vendors/DateJS/build/date-en-ZA.js @@ -0,0 +1,4526 @@ +/** + * @overview datejs + * @version 1.0.0-rc3 + * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-en-ZW.js b/vendors/DateJS/build/date-en-ZW.js
new file mode 100644
index 0000000..d33dfd5
--- /dev/null
+++ b/vendors/DateJS/build/date-en-ZW.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-AR.js b/vendors/DateJS/build/date-es-AR.js
new file mode 100644
index 0000000..7c33751
--- /dev/null
+++ b/vendors/DateJS/build/date-es-AR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-BO.js b/vendors/DateJS/build/date-es-BO.js
new file mode 100644
index 0000000..237ddd8
--- /dev/null
+++ b/vendors/DateJS/build/date-es-BO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-CL.js b/vendors/DateJS/build/date-es-CL.js
new file mode 100644
index 0000000..b729322
--- /dev/null
+++ b/vendors/DateJS/build/date-es-CL.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-CO.js b/vendors/DateJS/build/date-es-CO.js
new file mode 100644
index 0000000..e0a549b
--- /dev/null
+++ b/vendors/DateJS/build/date-es-CO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-CR.js b/vendors/DateJS/build/date-es-CR.js
new file mode 100644
index 0000000..ca53f55
--- /dev/null
+++ b/vendors/DateJS/build/date-es-CR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-DO.js b/vendors/DateJS/build/date-es-DO.js
new file mode 100644
index 0000000..b44fb79
--- /dev/null
+++ b/vendors/DateJS/build/date-es-DO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-EC.js b/vendors/DateJS/build/date-es-EC.js
new file mode 100644
index 0000000..bf7c371
--- /dev/null
+++ b/vendors/DateJS/build/date-es-EC.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-ES.js b/vendors/DateJS/build/date-es-ES.js
new file mode 100644
index 0000000..11d5302
--- /dev/null
+++ b/vendors/DateJS/build/date-es-ES.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-GT.js b/vendors/DateJS/build/date-es-GT.js
new file mode 100644
index 0000000..bb680e1
--- /dev/null
+++ b/vendors/DateJS/build/date-es-GT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-HN.js b/vendors/DateJS/build/date-es-HN.js
new file mode 100644
index 0000000..9b4f83c
--- /dev/null
+++ b/vendors/DateJS/build/date-es-HN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-MX.js b/vendors/DateJS/build/date-es-MX.js
new file mode 100644
index 0000000..a9dc0f3
--- /dev/null
+++ b/vendors/DateJS/build/date-es-MX.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-NI.js b/vendors/DateJS/build/date-es-NI.js
new file mode 100644
index 0000000..53d330d
--- /dev/null
+++ b/vendors/DateJS/build/date-es-NI.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-PA.js b/vendors/DateJS/build/date-es-PA.js
new file mode 100644
index 0000000..de9e8f6
--- /dev/null
+++ b/vendors/DateJS/build/date-es-PA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-PE.js b/vendors/DateJS/build/date-es-PE.js
new file mode 100644
index 0000000..72c4608
--- /dev/null
+++ b/vendors/DateJS/build/date-es-PE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-PR.js b/vendors/DateJS/build/date-es-PR.js
new file mode 100644
index 0000000..bff6a29
--- /dev/null
+++ b/vendors/DateJS/build/date-es-PR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-PY.js b/vendors/DateJS/build/date-es-PY.js
new file mode 100644
index 0000000..8340350
--- /dev/null
+++ b/vendors/DateJS/build/date-es-PY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-SV.js b/vendors/DateJS/build/date-es-SV.js
new file mode 100644
index 0000000..f713b96
--- /dev/null
+++ b/vendors/DateJS/build/date-es-SV.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-UY.js b/vendors/DateJS/build/date-es-UY.js
new file mode 100644
index 0000000..265c95c
--- /dev/null
+++ b/vendors/DateJS/build/date-es-UY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-es-VE.js b/vendors/DateJS/build/date-es-VE.js
new file mode 100644
index 0000000..48ce6e6
--- /dev/null
+++ b/vendors/DateJS/build/date-es-VE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-et-EE.js b/vendors/DateJS/build/date-et-EE.js
new file mode 100644
index 0000000..611c897
--- /dev/null
+++ b/vendors/DateJS/build/date-et-EE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-eu-ES.js b/vendors/DateJS/build/date-eu-ES.js
new file mode 100644
index 0000000..b13e08f
--- /dev/null
+++ b/vendors/DateJS/build/date-eu-ES.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fa-IR.js b/vendors/DateJS/build/date-fa-IR.js
new file mode 100644
index 0000000..d7777e9
--- /dev/null
+++ b/vendors/DateJS/build/date-fa-IR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fi-FI.js b/vendors/DateJS/build/date-fi-FI.js
new file mode 100644
index 0000000..7962642
--- /dev/null
+++ b/vendors/DateJS/build/date-fi-FI.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fo-FO.js b/vendors/DateJS/build/date-fo-FO.js
new file mode 100644
index 0000000..2d6fb99
--- /dev/null
+++ b/vendors/DateJS/build/date-fo-FO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-BE.js b/vendors/DateJS/build/date-fr-BE.js
new file mode 100644
index 0000000..90c9b8e
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-BE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-CA.js b/vendors/DateJS/build/date-fr-CA.js
new file mode 100644
index 0000000..3c3cca3
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-CA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-CH.js b/vendors/DateJS/build/date-fr-CH.js
new file mode 100644
index 0000000..7a668f4
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-CH.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-FR.js b/vendors/DateJS/build/date-fr-FR.js
new file mode 100644
index 0000000..c355664
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-FR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-LU.js b/vendors/DateJS/build/date-fr-LU.js
new file mode 100644
index 0000000..c5b2096
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-LU.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-fr-MC.js b/vendors/DateJS/build/date-fr-MC.js
new file mode 100644
index 0000000..5abf61f
--- /dev/null
+++ b/vendors/DateJS/build/date-fr-MC.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-gl-ES.js b/vendors/DateJS/build/date-gl-ES.js
new file mode 100644
index 0000000..c91414e
--- /dev/null
+++ b/vendors/DateJS/build/date-gl-ES.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-gu-IN.js b/vendors/DateJS/build/date-gu-IN.js
new file mode 100644
index 0000000..2394185
--- /dev/null
+++ b/vendors/DateJS/build/date-gu-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-he-IL.js b/vendors/DateJS/build/date-he-IL.js
new file mode 100644
index 0000000..88db194
--- /dev/null
+++ b/vendors/DateJS/build/date-he-IL.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-hi-IN.js b/vendors/DateJS/build/date-hi-IN.js
new file mode 100644
index 0000000..06c8437
--- /dev/null
+++ b/vendors/DateJS/build/date-hi-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-hr-BA.js b/vendors/DateJS/build/date-hr-BA.js
new file mode 100644
index 0000000..93276d1
--- /dev/null
+++ b/vendors/DateJS/build/date-hr-BA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-hr-HR.js b/vendors/DateJS/build/date-hr-HR.js
new file mode 100644
index 0000000..9267798
--- /dev/null
+++ b/vendors/DateJS/build/date-hr-HR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-hu-HU.js b/vendors/DateJS/build/date-hu-HU.js
new file mode 100644
index 0000000..9b8717c
--- /dev/null
+++ b/vendors/DateJS/build/date-hu-HU.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-hy-AM.js b/vendors/DateJS/build/date-hy-AM.js
new file mode 100644
index 0000000..425ac6a
--- /dev/null
+++ b/vendors/DateJS/build/date-hy-AM.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-id-ID.js b/vendors/DateJS/build/date-id-ID.js
new file mode 100644
index 0000000..d58fc97
--- /dev/null
+++ b/vendors/DateJS/build/date-id-ID.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-is-IS.js b/vendors/DateJS/build/date-is-IS.js
new file mode 100644
index 0000000..895413e
--- /dev/null
+++ b/vendors/DateJS/build/date-is-IS.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-it-CH.js b/vendors/DateJS/build/date-it-CH.js
new file mode 100644
index 0000000..d50e1c5
--- /dev/null
+++ b/vendors/DateJS/build/date-it-CH.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-it-IT.js b/vendors/DateJS/build/date-it-IT.js
new file mode 100644
index 0000000..0c6b826
--- /dev/null
+++ b/vendors/DateJS/build/date-it-IT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ja-JP.js b/vendors/DateJS/build/date-ja-JP.js
new file mode 100644
index 0000000..e7f6d76
--- /dev/null
+++ b/vendors/DateJS/build/date-ja-JP.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ka-GE.js b/vendors/DateJS/build/date-ka-GE.js
new file mode 100644
index 0000000..57a05c9
--- /dev/null
+++ b/vendors/DateJS/build/date-ka-GE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-kk-KZ.js b/vendors/DateJS/build/date-kk-KZ.js
new file mode 100644
index 0000000..35d39b4
--- /dev/null
+++ b/vendors/DateJS/build/date-kk-KZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-kn-IN.js b/vendors/DateJS/build/date-kn-IN.js
new file mode 100644
index 0000000..c139397
--- /dev/null
+++ b/vendors/DateJS/build/date-kn-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ko-KR.js b/vendors/DateJS/build/date-ko-KR.js
new file mode 100644
index 0000000..7979813
--- /dev/null
+++ b/vendors/DateJS/build/date-ko-KR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-kok-IN.js b/vendors/DateJS/build/date-kok-IN.js
new file mode 100644
index 0000000..f47b7e5
--- /dev/null
+++ b/vendors/DateJS/build/date-kok-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ky-KG.js b/vendors/DateJS/build/date-ky-KG.js
new file mode 100644
index 0000000..e375a2c
--- /dev/null
+++ b/vendors/DateJS/build/date-ky-KG.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-lt-LT.js b/vendors/DateJS/build/date-lt-LT.js
new file mode 100644
index 0000000..b4e853e
--- /dev/null
+++ b/vendors/DateJS/build/date-lt-LT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-lv-LV.js b/vendors/DateJS/build/date-lv-LV.js
new file mode 100644
index 0000000..8baa085
--- /dev/null
+++ b/vendors/DateJS/build/date-lv-LV.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-mi-NZ.js b/vendors/DateJS/build/date-mi-NZ.js
new file mode 100644
index 0000000..2dbb9a0
--- /dev/null
+++ b/vendors/DateJS/build/date-mi-NZ.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-mk-MK.js b/vendors/DateJS/build/date-mk-MK.js
new file mode 100644
index 0000000..861124e
--- /dev/null
+++ b/vendors/DateJS/build/date-mk-MK.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-mn-MN.js b/vendors/DateJS/build/date-mn-MN.js
new file mode 100644
index 0000000..64d3938
--- /dev/null
+++ b/vendors/DateJS/build/date-mn-MN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-mr-IN.js b/vendors/DateJS/build/date-mr-IN.js
new file mode 100644
index 0000000..c45ed09
--- /dev/null
+++ b/vendors/DateJS/build/date-mr-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ms-BN.js b/vendors/DateJS/build/date-ms-BN.js
new file mode 100644
index 0000000..7a284ec
--- /dev/null
+++ b/vendors/DateJS/build/date-ms-BN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ms-MY.js b/vendors/DateJS/build/date-ms-MY.js
new file mode 100644
index 0000000..82624d6
--- /dev/null
+++ b/vendors/DateJS/build/date-ms-MY.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-mt-MT.js b/vendors/DateJS/build/date-mt-MT.js
new file mode 100644
index 0000000..62c5612
--- /dev/null
+++ b/vendors/DateJS/build/date-mt-MT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-nb-NO.js b/vendors/DateJS/build/date-nb-NO.js
new file mode 100644
index 0000000..b5e6bf6
--- /dev/null
+++ b/vendors/DateJS/build/date-nb-NO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-nl-BE.js b/vendors/DateJS/build/date-nl-BE.js
new file mode 100644
index 0000000..b5cafc8
--- /dev/null
+++ b/vendors/DateJS/build/date-nl-BE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-nl-NL.js b/vendors/DateJS/build/date-nl-NL.js
new file mode 100644
index 0000000..4ced487
--- /dev/null
+++ b/vendors/DateJS/build/date-nl-NL.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-nn-NO.js b/vendors/DateJS/build/date-nn-NO.js
new file mode 100644
index 0000000..98a3de8
--- /dev/null
+++ b/vendors/DateJS/build/date-nn-NO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ns-ZA.js b/vendors/DateJS/build/date-ns-ZA.js
new file mode 100644
index 0000000..7d3175e
--- /dev/null
+++ b/vendors/DateJS/build/date-ns-ZA.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-pa-IN.js b/vendors/DateJS/build/date-pa-IN.js
new file mode 100644
index 0000000..6b730f7
--- /dev/null
+++ b/vendors/DateJS/build/date-pa-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-pl-PL.js b/vendors/DateJS/build/date-pl-PL.js
new file mode 100644
index 0000000..893ba72
--- /dev/null
+++ b/vendors/DateJS/build/date-pl-PL.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-pt-BR.js b/vendors/DateJS/build/date-pt-BR.js
new file mode 100644
index 0000000..83aebbd
--- /dev/null
+++ b/vendors/DateJS/build/date-pt-BR.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-pt-PT.js b/vendors/DateJS/build/date-pt-PT.js
new file mode 100644
index 0000000..1f4a380
--- /dev/null
+++ b/vendors/DateJS/build/date-pt-PT.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-quz-BO.js b/vendors/DateJS/build/date-quz-BO.js
new file mode 100644
index 0000000..9fc3274
--- /dev/null
+++ b/vendors/DateJS/build/date-quz-BO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-quz-EC.js b/vendors/DateJS/build/date-quz-EC.js
new file mode 100644
index 0000000..f0df98f
--- /dev/null
+++ b/vendors/DateJS/build/date-quz-EC.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-quz-PE.js b/vendors/DateJS/build/date-quz-PE.js
new file mode 100644
index 0000000..df5bc63
--- /dev/null
+++ b/vendors/DateJS/build/date-quz-PE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ro-RO.js b/vendors/DateJS/build/date-ro-RO.js
new file mode 100644
index 0000000..fe934b9
--- /dev/null
+++ b/vendors/DateJS/build/date-ro-RO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-ru-RU.js b/vendors/DateJS/build/date-ru-RU.js
new file mode 100644
index 0000000..ca16cb6
--- /dev/null
+++ b/vendors/DateJS/build/date-ru-RU.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-sa-IN.js b/vendors/DateJS/build/date-sa-IN.js
new file mode 100644
index 0000000..c43ab62
--- /dev/null
+++ b/vendors/DateJS/build/date-sa-IN.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-se-FI.js b/vendors/DateJS/build/date-se-FI.js
new file mode 100644
index 0000000..dd57864
--- /dev/null
+++ b/vendors/DateJS/build/date-se-FI.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-se-NO.js b/vendors/DateJS/build/date-se-NO.js
new file mode 100644
index 0000000..120de3c
--- /dev/null
+++ b/vendors/DateJS/build/date-se-NO.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config === "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.day) {
+ // If we should be a different date than today (eg: for 'tomorrow -1d', etc).
+ // Should only effect parsing, not direct usage (eg, Finish and FinishExact)
+ if ((x.day - this.getDate()) !== 0) {
+ this.setDate(x.day);
+ }
+ }
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used.
+ * Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function (utc) {
+ // Create a copy of this date object
+ var self, target = new Date(this.valueOf());
+ if (utc) {
+ target.addMinutes(target.getTimezoneOffset());
+ self = target.clone();
+ } else {
+ self = this;
+ }
+ // ISO week date weeks start on monday
+ // so correct the day number
+ var dayNr = (self.getDay() + 6) % 7;
+ // ISO 8601 states that week 1 is the week
+ // with the first thursday of that year.
+ // Set the target date to the thursday in the target week
+ target.setDate(target.getDate() - dayNr + 3);
+ // Store the millisecond value of the target date
+ var firstThursday = target.valueOf();
+ // Set the target to the first thursday of the year
+ // First set the target to january first
+ target.setMonth(0, 1);
+ // Not a thursday? Correct the date to the next thursday
+ if (target.getDay() !== 4) {
+ target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
+ }
+ // The weeknumber is the number of weeks between the
+ // first thursday of the year and the thursday in the target week
+ return 1 + Math.ceil((firstThursday - target) / 604800000); // 604800000 = 7 * 24 * 3600 * 1000
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ return p(this.getWeek(true));
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ if ((n - this.getWeek()) === 0) {
+ if (this.getDay() !== 1) {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1));
+ } else {
+ return this;
+ }
+ } else {
+ return this.moveToDayOfWeek(1, (this.getDay() > 1 ? -1 : 1)).addWeeks(n - this.getWeek());
+ }
+ };
+
+ $P.setQuarter = function (qtr) {
+ var month = Math.abs(((qtr-1) * 3) + 1);
+ return this.setMonth(month, 1);
+ };
+
+ $P.getQuarter = function () {
+ return Date.getQuarter(this);
+ };
+
+ $P.getDaysLeftInQuarter = function () {
+ return Date.getDaysLeftInQuarter(this);
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ if (dayOfWeek === "Weekday") {
+ if (occurrence > 0) {
+ this.moveToFirstDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence -= 1;
+ }
+ } else if (occurrence < 0) {
+ this.moveToLastDayOfMonth();
+ if (this.is().weekday()) {
+ occurrence += 1;
+ }
+ } else {
+ return this;
+ }
+ return this.addWeekdays(occurrence);
+ }
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+
+ var moveToN = function (getFunc, addFunc, nVal) {
+ return function (value, orient) {
+ var diff = (value - this[getFunc]() + nVal * (orient || +1)) % nVal;
+ return this[addFunc]((diff === 0) ? diff += nVal * (orient || +1) : diff);
+ };
+ };
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = moveToN("getDay", "addDays", 7);
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = moveToN("getMonth", "addMonths", 12);
+ /**
+ * Get the Ordinate of the current day ("th", "st", "rd").
+ * @return {String}
+ */
+ $P.getOrdinate = function () {
+ var num = this.getDate();
+ return ord(num);
+ };
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset(), this.isDaylightSavingTime());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return (there || there === 0) ? this.addMinutes(there - here) : this;
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function (offset) {
+ var n = (offset || this.getTimezoneOffset()) * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ config = validateConfigObject.call(this, config);
+ var key;
+ for (key in config) {
+ if (hasOwnProperty.call(config, key)) {
+ var name = key.charAt(0).toUpperCase() + key.slice(1);
+ var addFunc, getFunc;
+ if (key !== "week" && key !== "month" && key !== "timezone" && key !== "timezoneOffset") {
+ name += "s";
+ }
+ addFunc = "add" + name;
+ getFunc = "get" + name;
+ if (key === "month") {
+ addFunc = addFunc + "s";
+ } else if (key === "year"){
+ getFunc = "getFullYear";
+ }
+ if (key !== "day" && key !== "timezone" && key !== "timezoneOffset" && key !== "week" && key !== "hour") {
+ this[addFunc](config[key] - this[getFunc]());
+ } else if ( key === "timezone"|| key === "timezoneOffset" || key === "week" || key === "hour") {
+ this["set"+name](config[key]);
+ }
+ }
+ }
+ // day has to go last because you can't validate the day without first knowing the month
+ if (config.day) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ * CUSTOM DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * s The seconds of the minute between 0-59. "0" to "59"
+ * ss The seconds of the minute with leading zero if required. "00" to "59"
+ *
+ * m The minute of the hour between 0-59. "0" or "59"
+ * mm The minute of the hour with leading zero if required. "00" or "59"
+ *
+ * h The hour of the day between 1-12. "1" to "12"
+ * hh The hour of the day with leading zero if required. "01" to "12"
+ *
+ * H The hour of the day between 0-23. "0" to "23"
+ * HH The hour of the day with leading zero if required. "00" to "23"
+ *
+ * d The day of the month between 1 and 31. "1" to "31"
+ * dd The day of the month with leading zero if required. "01" to "31"
+ * ddd Abbreviated day name. Date.CultureInfo.abbreviatedDayNames. "Mon" to "Sun"
+ * dddd The full day name. Date.CultureInfo.dayNames. "Monday" to "Sunday"
+ *
+ * M The month of the year between 1-12. "1" to "12"
+ * MM The month of the year with leading zero if required. "01" to "12"
+ * MMM Abbreviated month name. Date.CultureInfo.abbreviatedMonthNames. "Jan" to "Dec"
+ * MMMM The full month name. Date.CultureInfo.monthNames. "January" to "December"
+ *
+ * yy The year as a two-digit number. "99" or "08"
+ * yyyy The full four digit year. "1999" or "2008"
+ *
+ * t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ * tt Displays the A.M./P.M. designator. "AM" or "PM"
+ * Date.CultureInfo.amDesignator or Date.CultureInfo.pmDesignator
+ *
+ * S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+ *
+ * STANDARD DATE AND TIME FORMAT STRINGS
+ * Format Description Example
+ *------ --------------------------------------------------------------------------- -----------------------
+ * d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ * D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ * F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ * m The CultureInfo monthDay Format Pattern "MMMM dd"
+ * r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ * s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ * t The CultureInfo shortTime Format Pattern "h:mm tt"
+ * T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ * u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ * y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+ var parseStandardFormats = function (format) {
+ var y, c = Date.CultureInfo.formatPatterns;
+ switch (format) {
+ case "d":
+ return this.toString(c.shortDate);
+ case "D":
+ return this.toString(c.longDate);
+ case "F":
+ return this.toString(c.fullDateTime);
+ case "m":
+ return this.toString(c.monthDay);
+ case "r":
+ case "R":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.rfc1123) + " GMT";
+ case "s":
+ return this.toString(c.sortableDateTime);
+ case "t":
+ return this.toString(c.shortTime);
+ case "T":
+ return this.toString(c.longTime);
+ case "u":
+ y = this.clone().addMinutes(this.getTimezoneOffset());
+ return y.toString(c.universalSortableDateTime);
+ case "y":
+ return this.toString(c.yearMonth);
+ default:
+ return false;
+ }
+ };
+ var parseFormatStringsClosure = function (context) {
+ return function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ switch (m) {
+ case "hh":
+ return p(context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12));
+ case "h":
+ return context.getHours() < 13 ? (context.getHours() === 0 ? 12 : context.getHours()) : (context.getHours() - 12);
+ case "HH":
+ return p(context.getHours());
+ case "H":
+ return context.getHours();
+ case "mm":
+ return p(context.getMinutes());
+ case "m":
+ return context.getMinutes();
+ case "ss":
+ return p(context.getSeconds());
+ case "s":
+ return context.getSeconds();
+ case "yyyy":
+ return p(context.getFullYear(), 4);
+ case "yy":
+ return p(context.getFullYear());
+ case "y":
+ return context.getFullYear();
+ case "E":
+ case "dddd":
+ return Date.CultureInfo.dayNames[context.getDay()];
+ case "ddd":
+ return Date.CultureInfo.abbreviatedDayNames[context.getDay()];
+ case "dd":
+ return p(context.getDate());
+ case "d":
+ return context.getDate();
+ case "MMMM":
+ return Date.CultureInfo.monthNames[context.getMonth()];
+ case "MMM":
+ return Date.CultureInfo.abbreviatedMonthNames[context.getMonth()];
+ case "MM":
+ return p((context.getMonth() + 1));
+ case "M":
+ return context.getMonth() + 1;
+ case "t":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
+ case "tt":
+ return context.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ case "S":
+ return ord(context.getDate());
+ case "W":
+ return context.getWeek();
+ case "WW":
+ return context.getISOWeek();
+ case "Q":
+ return "Q" + context.getQuarter();
+ case "q":
+ return String(context.getQuarter());
+ case "z":
+ return context.getTimezone();
+ case "Z":
+ case "X":
+ return Date.getTimezoneOffset(context.getTimezone());
+ case "ZZ": // Timezone offset in seconds
+ return context.getTimezoneOffset() * -60;
+ case "u":
+ return context.getDay();
+ case "L":
+ return ($D.isLeapYear(context.getFullYear())) ? 1 : 0;
+ case "B":
+ // Swatch Internet Time (.beats)
+ return "@"+((context.getUTCSeconds() + (context.getUTCMinutes()*60) + ((context.getUTCHours()+1)*3600))/86.4);
+ default:
+ return m;
+ }
+ };
+ };
+ $P.toString = function (format, ignoreStandards) {
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (!ignoreStandards && format && format.length === 1) {
+ output = parseStandardFormats.call(this, format);
+ if (output) {
+ return output;
+ }
+ }
+ var parseFormatStrings = parseFormatStringsClosure(this);
+ return format ? format.replace(/((\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S|q|Q|WW?W?W?)(?![^\[]*\]))/g, parseFormatStrings).replace(/\[|\]/g, "") : this._toString();
+ };
+
+}());
+/*************************************************************
+ * SugarPak - Domain Specific Language - Syntactical Sugar *
+ *************************************************************/
+
+(function () {
+ var $D = Date, $P = $D.prototype, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "days";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._move = true;
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._move = true;
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekday(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._nth) {
+ return df("Weekday").call(this);
+ }
+ if (this._move) {
+ return this.addWeekdays(this._orient);
+ }
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+ /**
+ * Determines if the current date is on the weekend. This function must be preceded by the .is() function.
+ * Example
+
+ Date.today().is().weekend(); // true|false
+
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekend = function () {
+ if (this._is) {
+ this._is = false;
+ return (this.is().sat() || this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {},
+ s = (this._dateElement[this._dateElement.length-1] !== "s") ? this._dateElement + "s" : this._dateElement;
+ c[s] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year Quarter Weekday").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear Quarter").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ if (this["get" + pxf[i]]) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() === n;
+ }
+ if (this._move) { this._move = null; }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && Date.CultureInfo.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var month_instance_functions = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var month_static_functions = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ var processTerms = function (names, staticFunc, instanceFunc) {
+ for (var i = 0; i < names.length; i++) {
+ // Create constant static Name variables.
+ $D[names[i].toUpperCase()] = $D[names[i].toUpperCase().substring(0, 3)] = i;
+ // Create Name functions.
+ $D[names[i]] = $D[names[i].substring(0, 3)] = staticFunc(i);
+ // Create Name instance functions.
+ $P[names[i]] = $P[names[i].substring(0, 3)] = instanceFunc(i);
+ }
+
+ };
+
+ processTerms(dx, sdf, df);
+ processTerms(mx, month_static_functions, month_instance_functions);
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ // the substr trick with -1 doesn't work in IE8 or less
+ k = (k[k.length-1] === "s") ? k.substring(0,k.length-1) : k;
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] !== o2[v]) {
+ return false;
+ }
+ if (k === v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) !== "s") {
+ j += "s";
+ }
+ if (this._move) { this._move = null; }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+ if(de !== "weekday") {
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de + "s");
+ }
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());
+
+(function () {
+ "use strict";
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+ var $P = Date.Parsing;
+ var dayOffsets = {
+ standard: [0,31,59,90,120,151,181,212,243,273,304,334],
+ leap: [0,31,60,91,121,152,182,213,244,274,305,335]
+ };
+
+ $P.isLeapYear = function(year) {
+ return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
+ };
+
+ var utils = {
+ multiReplace : function (str, hash ) {
+ var key;
+ for (key in hash) {
+ if (Object.prototype.hasOwnProperty.call(hash, key)) {
+ var regex;
+ if (typeof hash[key] === "function") {
+
+ } else {
+ regex = (hash[key] instanceof RegExp) ? hash[key] : new RegExp(hash[key], "g");
+ }
+ str = str.replace(regex, key);
+ }
+ }
+ return str;
+ },
+ getDayOfYearFromWeek : function (obj) {
+ var d, jan4, offset;
+ obj.weekDay = (!obj.weekDay && obj.weekDay !== 0) ? 1 : obj.weekDay;
+ d = new Date(obj.year, 0, 4);
+ jan4 = d.getDay() === 0 ? 7 : d.getDay(); // JS is 0 indexed on Sunday.
+ offset = jan4+3;
+ obj.dayOfYear = ((obj.week * 7) + (obj.weekDay === 0 ? 7 : obj.weekDay))-offset;
+ return obj;
+ },
+ getDayOfYear : function (obj, dayOffset) {
+ if (!obj.dayOfYear) {
+ obj = utils.getDayOfYearFromWeek(obj);
+ }
+ for (var i=0;i <= dayOffset.length;i++) {
+ if (obj.dayOfYear < dayOffset[i] || i === dayOffset.length) {
+ obj.day = obj.day ? obj.day : (obj.dayOfYear - dayOffset[i-1]);
+ break;
+ } else {
+ obj.month = i;
+ }
+ }
+ return obj;
+ },
+ adjustForTimeZone : function (obj, date) {
+ var offset;
+ if (obj.zone.toUpperCase() === "Z" || (obj.zone_hours === 0 && obj.zone_minutes === 0)) {
+ // it's UTC/GML so work out the current timeszone offset
+ offset = -date.getTimezoneOffset();
+ } else {
+ offset = (obj.zone_hours*60) + (obj.zone_minutes || 0);
+ if (obj.zone_sign === "+") {
+ offset *= -1;
+ }
+ offset -= date.getTimezoneOffset();
+ }
+ date.setMinutes(date.getMinutes()+offset);
+ return date;
+ },
+ setDefaults : function (obj) {
+ obj.year = obj.year || Date.today().getFullYear();
+ obj.hours = obj.hours || 0;
+ obj.minutes = obj.minutes || 0;
+ obj.seconds = obj.seconds || 0;
+ obj.milliseconds = obj.milliseconds || 0;
+ if (!(!obj.month && (obj.week || obj.dayOfYear))) {
+ // if we have a month, or if we don't but don't have the day calculation data
+ obj.month = obj.month || 0;
+ obj.day = obj.day || 1;
+ }
+ return obj;
+ },
+ dataNum: function (data, mod, explict, postProcess) {
+ var dataNum = data*1;
+ if (mod) {
+ if (postProcess) {
+ return data ? mod(data)*1 : data;
+ } else {
+ return data ? mod(dataNum) : data;
+ }
+ } else if (!explict){
+ return data ? dataNum : data;
+ } else {
+ return (data && typeof data !== "undefined") ? dataNum : data;
+ }
+ },
+ timeDataProcess: function (obj) {
+ var timeObj = {};
+ for (var x in obj.data) {
+ if (obj.data.hasOwnProperty(x)) {
+ timeObj[x] = obj.ignore[x] ? obj.data[x] : utils.dataNum(obj.data[x], obj.mods[x], obj.explict[x], obj.postProcess[x]);
+ }
+ }
+ if (obj.data.secmins) {
+ obj.data.secmins = obj.data.secmins.replace(",", ".") * 60;
+ if (!timeObj.minutes) {
+ timeObj.minutes = obj.data.secmins;
+ } else if (!timeObj.seconds) {
+ timeObj.seconds = obj.data.secmins;
+ }
+ delete obj.secmins;
+ }
+ return timeObj;
+ },
+ buildTimeObjectFromData: function (data) {
+ var time = utils.timeDataProcess({
+ data: {
+ year : data[1],
+ month : data[5],
+ day : data[7],
+ week : data[8],
+ dayOfYear : data[10],
+ hours : data[15],
+ zone_hours : data[23],
+ zone_minutes : data[24],
+ zone : data[21],
+ zone_sign : data[22],
+ weekDay : data[9],
+ minutes: data[16],
+ seconds: data[19],
+ milliseconds: data[20],
+ secmins: data[18]
+ },
+ mods: {
+ month: function(data) {
+ return data-1;
+ },
+ weekDay: function (data) {
+ data = Math.abs(data);
+ return (data === 7 ? 0 : data);
+ },
+ minutes: function (data) {
+ return data.replace(":","");
+ },
+ seconds: function (data) {
+ return Math.floor( (data.replace(":","").replace(",","."))*1 );
+ },
+ milliseconds: function (data) {
+ return (data.replace(",",".")*1000);
+ }
+ },
+ postProcess: {
+ minutes: true,
+ seconds: true,
+ milliseconds: true
+ },
+ explict: {
+ zone_hours: true,
+ zone_minutes: true
+ },
+ ignore: {
+ zone: true,
+ zone_sign: true,
+ secmins: true
+ }
+ });
+ return time;
+ },
+ addToHash: function (hash, keys, data) {
+ keys = keys;
+ data = data;
+ var len = keys.length;
+ for (var i = 0; i < len; i++) {
+ hash[keys[i]] = data[i];
+ }
+ return hash;
+ },
+ combineRegex: function (r1, r2) {
+ return new RegExp("(("+r1.source+")\\s("+r2.source+"))");
+ },
+ getDateNthString: function(add, last, inc){
+ if (add) {
+ return Date.today().addDays(inc).toString("d");
+ } else if (last) {
+ return Date.today().last()[inc]().toString("d");
+ }
+
+ },
+ buildRegexData: function (array) {
+ var arr = [];
+ var len = array.length;
+ for (var i=0; i < len; i++) {
+ if (Object.prototype.toString.call(array[i]) === '[object Array]') { // oldIE compat version of Array.isArray
+ arr.push(this.combineRegex(array[i][0], array[i][1]));
+ } else {
+ arr.push(array[i]);
+ }
+ }
+ return arr;
+ }
+ };
+
+ $P.processTimeObject = function (obj) {
+ var date, dayOffset;
+
+ utils.setDefaults(obj);
+ dayOffset = ($P.isLeapYear(obj.year)) ? dayOffsets.leap : dayOffsets.standard;
+
+ if (!obj.month && (obj.week || obj.dayOfYear)) {
+ utils.getDayOfYear(obj, dayOffset);
+ } else {
+ obj.dayOfYear = dayOffset[obj.month] + obj.day;
+ }
+
+ date = new Date(obj.year, obj.month, obj.day, obj.hours, obj.minutes, obj.seconds, obj.milliseconds);
+
+ if (obj.zone) {
+ utils.adjustForTimeZone(obj, date); // adjust (and calculate) for timezone
+ }
+ return date;
+ };
+
+ $P.ISO = {
+ regex : /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-4])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?\s?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/,
+ parse : function (s) {
+ var time, data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+
+ time = utils.buildTimeObjectFromData(data);
+
+ if (!time.year || (!time.year && (!time.month && !time.day) && (!time.week && !time.dayOfYear)) ) {
+ return null;
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Numeric = {
+ isNumeric: function (e){return!isNaN(parseFloat(e))&&isFinite(e);},
+ regex: /\b([0-1]?[0-9])([0-3]?[0-9])([0-2]?[0-9]?[0-9][0-9])\b/i,
+ parse: function (s) {
+ var data, i,
+ time = {},
+ order = Date.CultureInfo.dateElementOrder.split("");
+ if (!(this.isNumeric(s)) || // if it's non-numeric OR
+ (s[0] === "+" && s[0] === "-")) { // It's an arithmatic string (eg +/-1000)
+ return null;
+ }
+ if (s.length < 5 && s.indexOf(".") < 0 && s.indexOf("/") < 0) { // assume it's just a year.
+ time.year = s;
+ return $P.processTimeObject(time);
+ }
+ data = s.match(this.regex);
+ if (!data || !data.length) {
+ return null;
+ }
+ for (i=0; i < order.length; i++) {
+ switch(order[i]) {
+ case "d":
+ time.day = data[i+1];
+ break;
+ case "m":
+ time.month = (data[i+1]-1);
+ break;
+ case "y":
+ time.year = data[i+1];
+ break;
+ }
+ }
+ return $P.processTimeObject(time);
+ }
+ };
+
+ $P.Normalizer = {
+ regexData: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ return utils.buildRegexData([
+ $R.tomorrow,
+ $R.yesterday,
+ [$R.past, $R.mon],
+ [$R.past, $R.tue],
+ [$R.past, $R.wed],
+ [$R.past, $R.thu],
+ [$R.past, $R.fri],
+ [$R.past, $R.sat],
+ [$R.past, $R.sun]
+ ]);
+ },
+ basicReplaceHash : function() {
+ var $R = Date.CultureInfo.regexPatterns;
+ return {
+ "January": $R.jan.source,
+ "February": $R.feb,
+ "March": $R.mar,
+ "April": $R.apr,
+ "May": $R.may,
+ "June": $R.jun,
+ "July": $R.jul,
+ "August": $R.aug,
+ "September": $R.sep,
+ "October": $R.oct,
+ "November": $R.nov,
+ "December": $R.dec,
+ "": /\bat\b/gi,
+ " ": /\s{2,}/,
+ "am": $R.inTheMorning,
+ "9am": $R.thisMorning,
+ "pm": $R.inTheEvening,
+ "7pm":$R.thisEvening
+ };
+ },
+ keys : function(){
+ return [
+ utils.getDateNthString(true, false, 1), // tomorrow
+ utils.getDateNthString(true, false, -1), // yesterday
+ utils.getDateNthString(false, true, "monday"), //last mon
+ utils.getDateNthString(false, true, "tuesday"), //last tues
+ utils.getDateNthString(false, true, "wednesday"), //last wed
+ utils.getDateNthString(false, true, "thursday"), //last thurs
+ utils.getDateNthString(false, true, "friday"), //last fri
+ utils.getDateNthString(false, true, "saturday"), //last sat
+ utils.getDateNthString(false, true, "sunday") //last sun
+ ];
+ },
+ buildRegexFunctions: function () {
+ var $R = Date.CultureInfo.regexPatterns;
+ var __ = Date.i18n.__;
+ var tomorrowRE = new RegExp("(\\b\\d\\d?("+__("AM")+"|"+__("PM")+")? )("+$R.tomorrow.source.slice(1)+")", "i"); // adapted tomorrow regex for AM PM relative dates
+ var todayRE = new RegExp($R.today.source + "(?!\\s*([+-]))\\b"); // today, but excludes the math operators (eg "today + 2h")
+
+ this.replaceFuncs = [
+ [todayRE, function (full) {
+ return (full.length > 1) ? Date.today().toString("d") : full;
+ }],
+ [tomorrowRE,
+ function(full, m1) {
+ var t = Date.today().addDays(1).toString("d");
+ return (t + " " + m1);
+ }],
+ [$R.amThisMorning, function(str, am){return am;}],
+ [$R.pmThisEvening, function(str, pm){return pm;}]
+ ];
+
+ },
+ buildReplaceData: function () {
+ this.buildRegexFunctions();
+ this.replaceHash = utils.addToHash(this.basicReplaceHash(), this.keys(), this.regexData());
+ },
+ stringReplaceFuncs: function (s) {
+ for (var i=0; i < this.replaceFuncs.length; i++) {
+ s = s.replace(this.replaceFuncs[i][0], this.replaceFuncs[i][1]);
+ }
+ return s;
+ },
+ parse: function (s) {
+ s = this.stringReplaceFuncs(s);
+ s = utils.multiReplace(s, this.replaceHash);
+
+ try {
+ var n = s.split(/([\s\-\.\,\/\x27]+)/);
+ if (n.length === 3 &&
+ $P.Numeric.isNumeric(n[0]) &&
+ $P.Numeric.isNumeric(n[2]) &&
+ (n[2].length >= 4)) {
+ // ok, so we're dealing with x/year. But that's not a full date.
+ // This fixes wonky dateElementOrder parsing when set to dmy order.
+ if (Date.CultureInfo.dateElementOrder[0] === "d") {
+ s = "1/" + n[0] + "/" + n[2]; // set to 1st of month and normalize the seperator
+ }
+ }
+ } catch (e) {}
+
+ return s;
+ }
+ };
+ $P.Normalizer.buildReplaceData();
+}());
+(function () {
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function () { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\\s*" + s + "\\s*"))(s);
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ // Atomic Operators
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, cache_length = 0, cache_keys = [], CACHE_MAX = Date.Config.CACHE_MAX || 100000, r = null;
+ var cacheCheck = function () {
+ if (cache_length === CACHE_MAX) {
+ // kill several keys, don't want to have to do this all the time...
+ for (var i=0; i < 10; i++) {
+ var key = cache_keys.shift();
+ if (key) {
+ delete cache[key];
+ cache_length--;
+ }
+ }
+ }
+ };
+ return function (s) {
+ cacheCheck();
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ cache_length++;
+ cache_keys.push(s);
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length === 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length === 1);
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i !== j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ function gen() {
+ var args = null, rx = [], px, i;
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ px = args.shift();
+ if (px.length > 0) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ }
+
+ return gen;
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+(function () {
+ var $D = Date;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ var parseMeridian = function () {
+ if (this.meridian && (this.hour || this.hour === 0)) {
+ if (this.meridian === "a" && this.hour > 11 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12 && Date.Config.strict24hr){
+ throw "Invalid hour and meridian combination";
+ } else if (this.meridian === "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian === "a" && this.hour === 12) {
+ this.hour = 0;
+ }
+ }
+ };
+
+ var setDefaults = function () {
+ var now = new Date();
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+ if (!this.millisecond) {
+ this.millisecond = 0;
+ }
+ };
+
+ var finishUtils = {
+ getToday: function () {
+ if (this.now || "hour minute second".indexOf(this.unit) !== -1) {
+ return new Date();
+ } else {
+ return $D.today();
+ }
+ },
+ setDaysFromWeekday: function (today, orient){
+ var gap;
+ orient = orient || 1;
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ this.days = gap ? ((gap + (orient * 7)) % 7) : (orient * 7);
+ return this;
+ },
+ setMonthsFromMonth: function (today, orient) {
+ var gap;
+ orient = orient || 1;
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ this.months = gap ? ((gap + (orient * 12)) % 12) : (orient * 12);
+ this.month = null;
+ return this;
+ },
+ setDMYFromWeekday: function () {
+ var d = Date[this.weekday]();
+ this.day = d.getDate();
+ if (!this.month) {
+ this.month = d.getMonth();
+ }
+ this.year = d.getFullYear();
+ return this;
+ },
+ setUnitValue: function (orient) {
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator === "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+ },
+ generateDateFromWeeks: function () {
+ var weekday = (this.weekday !== undefined) ? this.weekday : "today";
+ var d = Date[weekday]().addWeeks(this.weeks);
+ if (this.now) {
+ d.setTimeToNow();
+ }
+ return d;
+ }
+ };
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ /* for ss.s format */
+ secondAndMillisecond: function (s) {
+ return function () {
+ var mx = s.match(/^([0-5][0-9])\.([0-9]{1,3})/);
+ this.second = Number(mx[1]);
+ this.millisecond = Number(mx[2]);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ if (this.day < 1) {
+ throw "invalid day";
+ }
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length === 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ if (this.month < 0) {
+ throw "invalid month";
+ }
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ var d;
+ x = (x instanceof Array) ? x : [x];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ setDefaults.call(this);
+ parseMeridian.call(this);
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ d = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ if (this.year < 100) {
+ d.setFullYear(this.year); // means years less that 100 are process correctly. JS will parse it otherwise as 1900-1999.
+ }
+ if (this.timezone) {
+ d.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ d.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return d;
+ },
+ finish: function (x) {
+ var today, expression, orient, temp;
+
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] === "function") {
+ x[i].call(this);
+ }
+ }
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else {
+ today = finishUtils.getToday.call(this);
+ }
+
+ expression = !!(this.days && this.days !== null || this.orient || this.operator);
+ orient = ((this.orient === "past" || this.operator === "subtract") ? -1 : 1);
+
+ if (this.month && this.unit === "week") {
+ this.value = this.month + 1;
+ delete this.month;
+ delete this.day;
+ }
+
+ if ((this.month || this.month === 0) && "year day hour minute second".indexOf(this.unit) !== -1) {
+ if (!this.value) {
+ this.value = this.month + 1;
+ }
+ this.month = null;
+ expression = true;
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ finishUtils.setDMYFromWeekday.call(this);
+ }
+
+ if (expression && this.weekday && this.unit !== "month" && this.unit !== "week") {
+ finishUtils.setDaysFromWeekday.call(this, today, orient);
+ }
+
+ if (this.weekday && this.unit !== "week" && !this.day && !this.days) {
+ temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if (this.month && this.unit === "day" && this.operator) {
+ if (!this.value) {
+ this.value = (this.month + 1);
+ }
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit === "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit !== "year") {
+ finishUtils.setMonthsFromMonth.call(this, today, orient);
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ finishUtils.setUnitValue.call(this, orient);
+ parseMeridian.call(this);
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit === "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (this.unit === "week" && this.weeks && !this.day && !this.month) {
+ return finishUtils.generateDateFromWeeks.call(this);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ if (expression){
+ today.add(this);
+ } else {
+ today.set(this);
+ }
+
+ if (this.timezone) {
+ this.timezone = this.timezone.toUpperCase();
+ var offset = $D.getTimezoneOffset(this.timezone);
+ var timezone;
+ if (today.hasDaylightSavingTime()) {
+ // lets check that we're being sane with timezone setting
+ timezone = $D.getTimezoneAbbreviation(offset, today.isDaylightSavingTime());
+ if (timezone !== this.timezone) {
+ // bugger, we're in a place where things like EST vs EDT matters.
+ if (today.isDaylightSavingTime()) {
+ today.addHours(-1);
+ } else {
+ today.addHours(1);
+ }
+ }
+ }
+ today.setTimezoneOffset(offset);
+ }
+
+ return today;
+ }
+ };
+}());
+(function () {
+ var $D = Date;
+ $D.Grammar = {};
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+ // Allow rolling up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = Date.CultureInfo.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken(Date.CultureInfo.regexPatterns[key]);
+ };
+ var cacheProcessRtoken = function (key, token, type, eachToken) {
+ if (eachToken) {
+ g[key] = _.cache(_.process(_.each(_.rtoken(token),_.optional(g.ctoken2(eachToken))), type));
+ } else {
+ g[key] = _.cache(_.process(_.rtoken(token), type));
+ }
+ };
+ var cacheProcessCtoken = function (token, type) {
+ return _.cache(_.process(g.ctoken2(token), type));
+ };
+ var _F = {}; //function cache
+
+ var _get = function (f) {
+ _F[f] = (_F[f] || g.format(f)[0]);
+ return _F[f];
+ };
+
+ g.allformats = function (fx) {
+ var rx = [];
+ if (fx instanceof Array) {
+ for (var i = 0; i < fx.length; i++) {
+ rx.push(_get(fx[i]));
+ }
+ } else {
+ rx.push(_get(fx));
+ }
+ return rx;
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ var grammarFormats = {
+ timeFormats: function(){
+ var i,
+ RTokenKeys = [
+ "h",
+ "hh",
+ "H",
+ "HH",
+ "m",
+ "mm",
+ "s",
+ "ss",
+ "ss.s",
+ "z",
+ "zz"
+ ],
+ RToken = [
+ /^(0[0-9]|1[0-2]|[1-9])/,
+ /^(0[0-9]|1[0-2])/,
+ /^([0-1][0-9]|2[0-3]|[0-9])/,
+ /^([0-1][0-9]|2[0-3])/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^([0-5][0-9]|[0-9])/,
+ /^[0-5][0-9]/,
+ /^[0-5][0-9]\.[0-9]{1,3}/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/,
+ /^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/
+ ],
+ tokens = [
+ t.hour,
+ t.hour,
+ t.hour,
+ t.minute,
+ t.minute,
+ t.second,
+ t.second,
+ t.secondAndMillisecond,
+ t.timezone,
+ t.timezone,
+ t.timezone
+ ];
+
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i]);
+ }
+
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ g.t = cacheProcessCtoken("shortMeridian", t.meridian);
+ g.tt = cacheProcessCtoken("longMeridian", t.meridian);
+ g.zzz = cacheProcessCtoken("timezone", t.timezone);
+
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+ },
+ dateFormats: function () {
+ // pre-loaded rules for different date part order preferences
+ var _setfn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ var i,
+ RTokenKeys = [
+ "d",
+ "dd",
+ "M",
+ "MM",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy"
+ ],
+ RToken = [
+ /^([0-2]\d|3[0-1]|\d)/,
+ /^([0-2]\d|3[0-1])/,
+ /^(1[0-2]|0\d|\d)/,
+ /^(1[0-2]|0\d)/,
+ /^(\d+)/,
+ /^(\d\d)/,
+ /^(\d\d?\d?\d?)/,
+ /^(\d\d\d\d)/
+ ],
+ tokens = [
+ t.day,
+ t.day,
+ t.month,
+ t.month,
+ t.year,
+ t.year,
+ t.year,
+ t.year
+ ],
+ eachToken = [
+ "ordinalSuffix",
+ "ordinalSuffix"
+ ];
+ for (i=0; i < RTokenKeys.length; i++) {
+ cacheProcessRtoken(RTokenKeys[i], RToken[i], tokens[i], eachToken[i]);
+ }
+
+ g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ g.mdy = _setfn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _setfn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _setfn(g.ddd, g.day, g.month, g.year);
+
+ g.date = function (s) {
+ return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
+ };
+ },
+ relative: function () {
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ }
+ };
+
+ g.buildGrammarFormats = function () {
+ // these need to be rebuilt every time the language changes.
+ _C = {};
+
+ grammarFormats.timeFormats();
+ grammarFormats.dateFormats();
+ grammarFormats.relative();
+
+
+ g.value = _.process(_.rtoken(/^([-+]?\d+)?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?(?!e)|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(_.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )
+ ),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+ };
+
+ g.buildGrammarFormats();
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ss.sz",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+}());
+(function () {
+ var $D = Date;
+
+ /**
+ * @desc Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ var parseUtils = {
+ removeOrds: function (s) {
+ ords = s.match(/\b(\d+)(?:st|nd|rd|th)\b/); // find ordinal matches
+ s = ((ords && ords.length === 2) ? s.replace(ords[0], ords[1]) : s);
+ return s;
+ },
+ grammarParser: function (s) {
+ var r = null;
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+
+ return ((r[1].length === 0) ? r[0] : null);
+ },
+ nativeFallback: function(s) {
+ var t;
+ try {
+ // ok we haven't parsed it, last ditch attempt with the built-in parser.
+ t = Date._parse(s);
+ return (t || t === 0) ? new Date(t) : null;
+ } catch (e) {
+ return null;
+ }
+ }
+ };
+ function parse (s) {
+ var d;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s.clone();
+ }
+ if (s.length >= 4 && s.charAt(0) !== "0" && s.charAt(0) !== "+"&& s.charAt(0) !== "-") { // ie: 2004 will pass, 0800 won't.
+ // Start with specific formats
+ d = $D.Parsing.ISO.parse(s) || $D.Parsing.Numeric.parse(s);
+ }
+ if (d instanceof Date && !isNaN(d.getTime())) {
+ return d;
+ } else {
+ // find ordinal dates (1st, 3rd, 8th, etc and remove them as they cause parsing issues)
+ s = $D.Parsing.Normalizer.parse(parseUtils.removeOrds(s));
+ d = parseUtils.grammarParser(s);
+ if (d !== null) {
+ return d;
+ } else {
+ return parseUtils.nativeFallback(s);
+ }
+ }
+ }
+
+ if (!$D._parse) {
+ $D._parse = $D.parse;
+ }
+ $D.parse = parse;
+
+ Date.getParseFunction = function (fx) {
+ var fns = Date.Grammar.allformats(fx);
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < fns.length; i++) {
+ try {
+ r = fns[i].call({}, s);
+ } catch (e) {
+ continue;
+ }
+ if (r[1].length === 0) {
+ return r[0];
+ }
+ }
+ return null;
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ // $C = $D.CultureInfo, // not used atm
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with ._format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ * var f1 = "%m/%d/%y"
+ * var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+ *
+ * new Date().format(f1); // "04/13/08"
+ * new Date()._format(f1); // "04/13/08"
+ * new Date().toString(f2); // "04/13/08"
+ *
+ * var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ *
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ var normalizerSubstitutions = {
+ "d" : "dd",
+ "%d": "dd",
+ "D" : "ddd",
+ "%a": "ddd",
+ "j" : "dddd",
+ "l" : "dddd",
+ "%A": "dddd",
+ "S" : "S",
+ "F" : "MMMM",
+ "%B": "MMMM",
+ "m" : "MM",
+ "%m": "MM",
+ "M" : "MMM",
+ "%b": "MMM",
+ "%h": "MMM",
+ "n" : "M",
+ "Y" : "yyyy",
+ "%Y": "yyyy",
+ "y" : "yy",
+ "%y": "yy",
+ "g" : "h",
+ "%I": "h",
+ "G" : "H",
+ "h" : "hh",
+ "H" : "HH",
+ "%H": "HH",
+ "i" : "mm",
+ "%M": "mm",
+ "s" : "ss",
+ "%S": "ss",
+ "%r": "hh:mm tt",
+ "%R": "H:mm",
+ "%T": "H:mm:ss",
+ "%X": "t",
+ "%x": "d",
+ "%e": "d",
+ "%D": "MM/dd/yy",
+ "%n": "\\n",
+ "%t": "\\t",
+ "e" : "z",
+ "T" : "z",
+ "%z": "z",
+ "%Z": "z",
+ "Z" : "ZZ",
+ "N" : "u",
+ "w" : "u",
+ "%w": "u",
+ "W" : "W",
+ "%V": "W"
+ };
+ var normalizer = {
+ substitutes: function (m) {
+ return normalizerSubstitutions[m];
+ },
+ interpreted: function (m, x) {
+ var y;
+ switch (m) {
+ case "%u":
+ return x.getDay() + 1;
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+
+ case "%W":
+ return p(x.getWeek());
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x._format("%G").slice(-2);
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ }
+ },
+ shouldOverrideDefaults: function (m) {
+ switch (m) {
+ case "%e":
+ return true;
+ default:
+ return false;
+ }
+ },
+ parse: function (m, context) {
+ var formatString, c = context || new Date();
+ formatString = normalizer.substitutes(m);
+ if (formatString) {
+ return formatString;
+ }
+ formatString = normalizer.interpreted(m, c);
+
+ if (formatString) {
+ return formatString;
+ } else {
+ return m;
+ }
+ }
+ };
+
+ $D.normalizeFormat = function (format, context) {
+ return format.replace(/(%|\\)?.|%%/g, function(t){
+ return normalizer.parse(t, context);
+ });
+ };
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example:
+ * Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ * Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number|String} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ var d = Date.parse(time);
+ return d._format(format);
+ };
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example:
+ * Date.strtotime("04/13/08"); // 1208044800
+ * Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ *
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ * Format Specifiers
+ * Format Description Example
+ * ------ --------------------------------------------------------------------------- -----------------------
+ * %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ * %A full weekday name according to the current localed "Sunday" through "Saturday"
+ * %b abbreviated month name according to the current localed "Jan" through "Dec"
+ * %B full month name according to the current locale "January" through "December"
+ * %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ * %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ * %d day of the month as a decimal number "01" to "31"
+ * %D same as %m/%d/%y "04/13/08"
+ * %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ * %g like %G, but without the century "08"
+ * %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ * This has the same format and value as %Y, except that if the ISO week number
+ * belongs to the previous or next year, that year is used instead.
+ * %h same as %b "Jan" through "Dec"
+ * %H hour as a decimal number using a 24-hour clock. "00" to "23"
+ * %I hour as a decimal number using a 12-hour clock. "01" to "12"
+ * %j day of the year as a decimal number. "001" to "366"
+ * %m month as a decimal number. "01" to "12"
+ * %M minute as a decimal number. "00" to "59"
+ * %n newline character "\n"
+ * %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ * corresponding strings for the current locale.
+ * %r time in a.m. and p.m. notation "8:44 PM"
+ * %R time in 24 hour notation "20:44"
+ * %S second as a decimal number "00" to "59"
+ * %t tab character "\t"
+ * %T current time, equal to %H:%M:%S "12:49:11"
+ * %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ * %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ * first Sunday as the first day of the first week
+ * %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ * range 01 to 53, where week 1 is the first week that has at least 4 days
+ * in the current year, and with Monday as the first day of the week.
+ * (Use %G or %g for the year component that corresponds to the week number
+ * for the specified timestamp.)
+ * %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ * first Monday as the first day of the first week
+ * %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ * %x preferred date representation for the current locale without the time "4/13/2008"
+ * %X preferred time representation for the current locale without the date "12:53:05"
+ * %y year as a decimal number without a century "00" "99"
+ * %Y year as a decimal number including the century "2008"
+ * %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ * %z same as %Z
+ * %% a literal "%" characters "%"
+ * d Day of the month, 2 digits with leading zeros "01" to "31"
+ * D A textual representation of a day, three letters "Mon" through "Sun"
+ * j Day of the month without leading zeros "1" to "31"
+ * l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ * N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ * S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ * w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ * z The day of the year (starting from "0") "0" through "365"
+ * W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ * F A full textual representation of a month, such as January or March "January" through "December"
+ * m Numeric representation of a month, with leading zeros "01" through "12"
+ * M A short textual representation of a month, three letters "Jan" through "Dec"
+ * n Numeric representation of a month, without leading zeros "1" through "12"
+ * t Number of days in the given month "28" through "31"
+ * L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ * o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ * ISO week number (W) belongs to the previous or next year, that year
+ * is used instead.
+ * Y A full numeric representation of a year, 4 digits "2008"
+ * y A two digit representation of a year "08"
+ * a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ * A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ * B Swatch Internet time "000" through "999"
+ * g 12-hour format of an hour without leading zeros "1" through "12"
+ * G 24-hour format of an hour without leading zeros "0" through "23"
+ * h 12-hour format of an hour with leading zeros "01" through "12"
+ * H 24-hour format of an hour with leading zeros "00" through "23"
+ * i Minutes with leading zeros "00" to "59"
+ * s Seconds, with leading zeros "00" through "59"
+ * u Milliseconds "54321"
+ * e Timezone identifier "UTC", "EST", "PST"
+ * I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ * O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ * P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ * T Timezone abbreviation "UTC", "EST", "PST"
+ * Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ * always negative, and for those east of UTC is always positive.
+ * c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ * r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ var formatReplace = function (context) {
+ return function (m) {
+ var formatString, override = false;
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+
+ override = normalizer.shouldOverrideDefaults(m);
+ formatString = $D.normalizeFormat(m, context);
+ if (formatString) {
+ return context.toString(formatString, override);
+ }
+ };
+ };
+ $P._format = function (format) {
+ var formatter = formatReplace(this);
+ if (!format) {
+ return this._toString();
+ } else {
+ return format.replace(/(%|\\)?.|%%/g, formatter);
+ }
+ };
+
+ if (!$P.format) {
+ $P.format = $P._format;
+ }
+}());
+(function () {
+ "use strict";
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+ /**
+ * new TimeSpan(milliseconds);
+ * new TimeSpan(days, hours, minutes, seconds);
+ * new TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+ var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 1 && typeof days === "number") {
+ var orient = (days < 0) ? -1 : +1;
+ var millsLeft = Math.abs(days);
+ this.setDays(Math.floor(millsLeft / 86400000) * orient);
+ millsLeft = millsLeft % 86400000;
+ this.setHours(Math.floor(millsLeft / 3600000) * orient);
+ millsLeft = millsLeft % 3600000;
+ this.setMinutes(Math.floor(millsLeft / 60000) * orient);
+ millsLeft = millsLeft % 60000;
+ this.setSeconds(Math.floor(millsLeft / 1000) * orient);
+ millsLeft = millsLeft % 1000;
+ this.setMilliseconds(millsLeft * orient);
+ } else {
+ this.set(days, hours, minutes, seconds, milliseconds);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) +
+ (this.getHours() * 3600000) +
+ (this.getMinutes() * 60000) +
+ (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ } else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+ };
+ addSetFuncs(TimeSpan, attrs.slice(2));
+ TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+
+ /**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+ Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+ };
+
+ Date.TimeSpan = TimeSpan;
+
+ if (typeof window !== "undefined" ) {
+ // keeping API compatible for v1.x
+ window.TimeSpan = TimeSpan;
+ }
+}());
+(function () {
+ "use strict";
+ var attrs = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"];
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+ var addSetFuncs = function (context, attrs) {
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ context.prototype[$a] = 0;
+ context.prototype["get" + $b] = gFn($a);
+ context.prototype["set" + $b] = sFn($a);
+ }
+ };
+
+ var setMonthsAndYears = function (orient, d1, d2, context) {
+ function inc() {
+ d1.addMonths(-orient);
+ context.months++;
+ if (context.months === 12) {
+ context.years++;
+ context.months = 0;
+ }
+ }
+ if (orient === +1) {
+ while (d1 > d2) {
+ inc();
+ }
+ } else {
+ while (d1 < d2) {
+ inc();
+ }
+ }
+ context.months--;
+ context.months *= orient;
+ context.years *= orient;
+ };
+
+ var adjustForDST = function(orient, startDate, endDate) {
+ var hasDSTMismatch = (false === (startDate.isDaylightSavingTime() === endDate.isDaylightSavingTime()));
+ if (hasDSTMismatch && orient === 1) {
+ startDate.addHours(-1);
+ } else if (hasDSTMismatch) {
+ startDate.addHours(1);
+ }
+ };
+ /**
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+ var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ if (arguments.length === 7) {
+ this.set(years, months, days, hours, minutes, seconds, milliseconds);
+ } else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ var startDate = arguments[0].clone();
+ var endDate = arguments[1].clone();
+ var orient = (startDate > endDate) ? +1 : -1;
+ this.dates = {
+ start: arguments[0].clone(),
+ end: arguments[1].clone()
+ };
+
+ setMonthsAndYears(orient, startDate, endDate, this);
+ adjustForDST(orient, startDate, endDate);
+ // // TODO - adjust for DST
+ var diff = endDate - startDate;
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.set(this.years, this.months, ts.getDays(), ts.getHours(), ts.getMinutes(), ts.getSeconds(), ts.getMilliseconds());
+ }
+ }
+ return this;
+ };
+ // create all the set functions.
+ addSetFuncs(TimePeriod, attrs);
+ TimePeriod.prototype.set = function (years, months, days, hours, minutes, seconds, milliseconds){
+ this.setYears(years || this.getYears());
+ this.setMonths(months || this.getMonths());
+ this.setDays(days || this.getDays());
+ this.setHours(hours || this.getHours());
+ this.setMinutes(minutes || this.getMinutes());
+ this.setSeconds(seconds || this.getSeconds());
+ this.setMilliseconds(milliseconds || this.getMilliseconds());
+ };
+
+ Date.TimePeriod = TimePeriod;
+
+ if (typeof window !== "undefined") {
+ // keeping API compatible for v1.x
+ window.TimePeriod = TimePeriod;
+ }
+}());
\ No newline at end of file
diff --git a/vendors/DateJS/build/date-se-SE.js b/vendors/DateJS/build/date-se-SE.js
new file mode 100644
index 0000000..b56ff77
--- /dev/null
+++ b/vendors/DateJS/build/date-se-SE.js
@@ -0,0 +1,4526 @@
+/**
+ * @overview datejs
+ * @version 1.0.0-rc3
+ * @author Gregory Wild-Smith